Sripathi Krishnan
#Django | 24 Min Read

Designing Modules in Python is part of HashedIn’s training program for junior developers to get better at design. Today, we are making it available as a free ebook.

Download E-Book

Who is this ebook for?

This book is for all those who have some experience in an object-oriented programming language. If you wish to get better at the module or class level design, then this book is definitely for you. You will be able to identify a good design from the bad after you finish reading this book
All throughout this book, python is used to introduce various design patterns. However, the knowledge of python is not mandatory. If you can understand classes and methods, you will easily be able to understand the contents of this book

How to use this book

To make the most of this book, read the requirements at the start of each chapter and write down your solution. Then read through the rest of the chapter and critique your solution.
Good design is obvious once presented. However, arriving at that solution is difficult, especially if you are new to programming. Writing down your solution is the only way to realize the shortcomings of your design. If you read the chapter without writing, you will tell yourself “That was obvious. I would have solved it in a similar manner”

History of this book

At HashedIn, we conduct a training program for junior developers to get better at design. During one of these programs, we asked developers to design a module to send SMS/text messages. We also asked them to call the SMS module from 3 different client applications. They had 30 minutes to complete this activity.
After 30 minutes, we revealed a new set of requirements. Additionally, we set 2 hard rules for them to implement these requirements:

  1. Developers were not allowed to change the way client applications invoked their SMS module
  2. Developers were not allowed to modify existing code. Instead, they had to write new code to address the additional requirements, without duplicating code.

20 minutes later, we again introduced a new set of requirements. And after another 20 minutes, we introduced the final set of requirements.
Initially, the developers felt the problem was very simple. They were at loss to understand why the design was even needed. Isn’t this a simple python function?
But as new requirements emerged, and because we gave them constraints (don’t change existing code) – they began to appreciate the various design principles. Some even developed a mental model to discern good design from bad.
Over time, we got the opportunity to review designs from several developers. We learned how junior developers think when asked to solve a problem. Based on these patterns, we wrote a series of blogs on how to design modules in python.

Design Modules in Python

Python Interface Design

The first module will teach you as to how you can design a reusable python module. By the end of the post, you will get a great understanding of writing reusable and extensible modules in python.

You have been given the following requirements:

You are the developer on Blipkart, an e-commerce website. You have been asked to build a reusable SMS module that other developers will use to send SMS’es. Watertel is a telecom company that provides a REST API for sending SMS’es, and your module needs to integrate with Watertel. Your module will be used by other modules such as logistics.py and orders.py.


The first goal for a module should be good Abstraction. Your module sits between client developers on one side, and the API provided by Watertel on the other side. The module’s job is to simplify sending an SMS, and to ensure that changes in Watertel do not affect your client developers.

The essence of abstractions is preserving information that is relevant in a given context, and forgetting information that is irrelevant in that context.

Watertel exposes these concepts – username, password, access_token and expiry, phone number, message, and priority. Which of these concepts are relevant to client developers?

Client developers don’t care about username and password. They don’t want to worry about expiry either. These are things our module should handle. They only care about phone number and message – “take this message, and send it to this phone number”.

Interface Design

Since developers only care about phone_number and message, our interface design is very clear – we need a send_sms(phone_number, message) function. Everything else is irrelevant.

Now, looking from an implementation perspective. We need the URL, the username, and password. We also need to manage the access token and handle its expiry. How will we get this information? Let’s carve out an interface design for our solution.

In general, if you need some information, or if you depend on other classes – you must get it via your constructor. Your class must not go about trying to find that information on its own (say from Django settings).

Here’s how our interface looks like:

# sms.py:
class SmsClient:
    def __init__(self, url, username, password):
        self.username = username
        self.password = password
    def send_sms(phone_number, message):
        # TODO - write code to send sms
        pass

Using our Class in Client Code

Next, in order to use our module, our clients need an object of SmsClient. But in order to create an object, they’d need username and password. Our first attempt would be something like this:

# In orders.py
from django.conf import settings
from sms import SmsClient
sms_client = SmsClient(settings.sms_url, settings.sms_username, settings.sms_password)
....
sms_client.send_sms(phone_number, message)

There are two problems with this:

  1. First, orders.py shouldn’t care how SmsClient objects are constructed. If we later need additional parameters in the constructor, we would have to change orders.py, and all classes that use SmsClient. Also, if we decide to read our settings from someplace else (say for test cases), then orders.py would have to be modified.
  2. The second problem is that we would have to create SmsClient objects everywhere we want to use it. This is wasteful, and also leads to code duplication.

The solution is to create SmsClient object in sms.py module [see footnote 1]. Then orders.py and logistics.py can directly import the object from SMS. Here is how it looks.

# In sms.py:
from django.conf import settings
class SmsClient:
    def __init__(self, url, username, password):
        self.username = username
        self.password = password
    def send_sms(phone_number, message):
        # TODO - write code to send sms
        pass
sms_client = SmsClient(settings.sms_url, settings.sms_username, settings.sms_password)

and in orders.py:

# orders.py
from sms import sms_client
...
# when you need to send an sms
sms_client.send_sms(phone_number, message)

Before you start implementing, think about how your clients will use your module. It’s a good idea to actually write down the client code (i.e. code in orders.py and logistics.py) before you start implementing your module.

Now that we have our interface defined, we can start implementing our module.

Python Dependency Injection

Next step is to learn as to how python design patterns can be benefited from dependency injection.

Here we discuss how python module designing be benefited from dependency injection. You have been given the following requirements:

You are the developer on Blipkart, an e-commerce website. You have been asked to build a reusable SMS module that other developers will use to send SMS’es. Watertel is a telecom company that provides a REST API for sending SMS’es, and your module needs to integrate with Watertel. Your module will be used by other modules such as logistics.py and orders.py.


The client modules have a dependency on our module to complete a portion of its work which is – sending an SMS. So our module’s object has to be injected in the client’s module through the respective modules do not know each other directly.

Why Dependency Injection?

The essence of dependency injection is that it allows the client to remove all knowledge of a concrete implementation that it needs to use. This helps isolate the client from the impact of design changes and defects. It promotes reusability, testability and maintainability.

Basically, instead of having your objects creating a dependency or asking a factory object to make one for them, you pass the needed dependencies into the object externally, and you make it somebody else’s problem. This “someone” is either an object further up the dependency graph, or a dependency injector (framework) that builds the dependency graph. A dependency as I’m using it here is any other object the current object needs to hold a reference to.

The client modules ie. orders.py and logistics.py can import our module’s object and then inject it where it needs the module to perform its task.

This will explain how it should look like.

# In sms.py:
from django.conf import settings
class SmsClient:
    def __init__(self, url, username, password):
        self.username = username
        self.password = password
    def send_sms(phone_number, message):
        # TODO - write code to send sms
        pass
sms_client = SmsClient(settings.sms_url, settings.sms_username, settings.sms_password)

and in orders.py:

# orders.py
from sms import sms_client
...
# when you need to send an sms
sms_client.send_sms(phone_number, message)

How does Dependency Injection help us?

  1. 1. Dependency Injection decreases coupling between a class and its dependency.
  2. 2.Because dependency injection doesn’t require any change in code behavioDependencybe applied to legacy code as a refactoring. The result is clients that are more independent and that are easier to unit test in isolation using stubs or mock objects that simulate other objects not under test. This ease of testing is often the first benefit noticed when using dependency injection.
  3. 3. To free modules from assumptions about how other systems do what they do and instead rely on contract.
  4. 4. To prevent side effects when replacing a module.

So in all, dependency injection is a great practice to make our modules more testable, maintainable and scalable and we should use it more often to make our lives easier as developers.

Exception Handling In Python

Now we will have a detailed discussion on the Exception Handling in Python. We will discuss in detail, the implementation of a robust SMS module.

To start sending SMS’es, we need to first login to Watertel, store the accessToken and the time when the accessToken expires.

# sms.py
class SmsClient:
    def __init__(self, url, username, password):
        self.url = url
        self.username = username
        self.password = password
        self.access_token = None
        self.expires_at = 0
    def _login(self):
        # TODO - Make HTTPS request, get accessToken and expiresAt
        # TODO - error handling, check status codes
        self.access_token = response["accessToken"]
        self.expires_at = get_current_time() + response["expiry"]

You don’t expect or want client developers to think about login, hence we make the login method private (start with the underscore).
Now we need to decide who calls the _login method. One easy (and wrong) choice, is calling the _login method from our constructor. Constructors must not do real work, but only aid in initialization. If we make network calls in the constructor, it makes the object difficult to test, and difficult to reuse.
So _login cannot be called by clients, and cannot be called in the constructor. Which leaves us with only one choice – call _login from the send_sms method. And while we are at it, we will add another wrapper to directly get us the access_token without worrying about expiry. This also gives the necessary modularity to our code.

def _get_access_token(self):
    if (get_current_time() > self.expires_at):
        self._login()
    return self.access_token
def send_sms(self, phone_number, message):
    access_token = self._get_access_token()
    # TODO: use the access_token to make an API call and send the SMS

At this point we can start writing code to send the SMS. We will assume a make_request function that returns the parsed JSON object and the http status code.

def send_sms(self, phone_number, message):
    access_token = self._get_access_token()
    status_code, response = _make_http_request(access_token, phone_number, message)
    ...

Error Handling in Python – Status Codes

What should we do with the status_code? One option is to return the status_code and let our clients handle it. And that is a bad idea.
We don’t want our clients to know how we are sending the SMS. This is important – if the clients know how you send the SMS, you cannot change how your module works in the future. When we return the HTTP status code, we are telling them indirectly how our module works. This is called a leaky abstraction, and you want to avoid it as much as possible (though you can’t eliminate it completely).
So to give our code the much-needed abstraction, we will not return the status code, but we still want our clients to do some error handling. Since our clients are calling a python method, they expect to receive errors the pythonic way – using Exception Handling in Python.
When it comes to error handling, you need to be clear whose problem it is. It’s either the client developer’s fault or your module’s fault. A problem with your module’s dependency (i.e. Watertel server down) is also your module’s fault – because the client developer doesn’t know Watertel even exists.
We will create an exception class for each possible error in the module –

  • BadInputError – a base error for incorrect inputs
  • InvalidPhoneNumberError – when the phone number is malformed or wrong
  • InvalidMessageError – when the message is longer than 140 characters
  • SmsException – when it’s our modules fault and we cannot send the SMS. This tells our clients that calling send_sms again is safe and may work.

On implementing python exception handling, here is how our code looks like:

def _validate_phone_number(self, phone_number):
    if not phone_number:
        raise InvalidPhoneNumberError("Empty phone number")
    phone_number = phone_number.strip()
    if (len(phone_number) > 10):
        raise InvalidPhoneNumberError("Phone number too long")
    # TODO add more such checks
def _validate_message(self, message):
    if not message:
        raise InvalidMessageError("Empty message")
    if (len(message) > 140):
        raise InvalidMessageError("Message too long")
def send_sms(self, phone_number, message):
    self._validate_phone_number(phone_number)
    self._validate_message(message)
    access_token = self._get_access_token()
    status_code, response = _make_http_request(access_token, phone_number, message)
    if (status_code == 400):
        # This is Watertel telling us the input is incorrect
        # If it is possible, we should read the error message
        # and try to convert it to a proper error
        # We will just raise the generic BadInputError
        raise BadInputError(response.error_message)
     elif (status_code in (300, 301, 302, 401, 403)):
         # These status codes indicate something is wrong
         # with our module's logic. Retrying won't help,
         # we will keep getting the same status code
         # 3xx is a redirect, indicate a wrong url
         # 401, 403 have got to do with the access_token being wrong
         # We don't want our clients to retry, so we raise RuntimeError
         raise RuntimeError(response.error_message)
      elif (status_code > 500):
         # This is a problem with Watertel
         # This is beyond our control, and perhaps retrying would help
         # We indicate this by raising SmsException
         raise SmsException(response.error_message)

Error Handling in Python – Exceptions

Apart from error handling of status codes, there’s one more thing that is missing – handling any exceptions that are raised by _make_request. Assuming you are using the wonderful requests library, this is the list of exceptions that can be thrown.
You can categorize these exceptions into two categories – safe to retry v/s not safe to retry. If it is safe to retry, wrap the exception in a SMSException and raise it. Otherwise, just let the exception propagate.
In our case, ConnectTimeout is safe to retry. ReadTimeout indicates the request made it to the server, but the server did not respond timely. In such cases, you can’t be sure if the SMS was sent or not. If it is critical the SMS be sent, you should retry. If your end users would be annoyed receiving multiple SMSes, then do not retry.
You can handle these exceptions inside the _make_request method.

def _make_http_request(access_token, phone_number, message):
    try:
        data = {"message": message, "phone": phone_number, "priority": self.priority}
        url = "%s?accessToken=%s" % (self.url, access_token)
        r = requests.post(url, json=data)
        return (r.status_code, r.json())
    except ConnectTimeout:
        raise SmsException("Connection timeout trying to send SMS")

This should have given you a gist of how exception handling in python can help build a cleaner and more robust code.
That covers most of the implementation of our module. We won’t get into the code that actually makes the HTTP request – you can use the requests library for that.

So,

  1. Don’t leak inner workings of your module to your clients, otherwise, you can never refactor or change your implementation.
  2. Raise appropriate Errors to inform your clients about what went wrong.

Open Closed Principle in Python

The open/closed principle teaches us not to modify our already working code just for adding new features.

New Requirements – Retry Failed SMS’es

We now have a feature request from the product managers:

Customers are complaining that they don’t receive SMS’es at times. Watertel recommends resending the SMS if the status code is 5xx. Hence we need to extend the sms module to support retries with exponential backoff. The first retry should be immediate, the next retry within 2s, and the third retry within 4s. If it still continues to fail, give up and don’t try further.

Of course, our product manager assumed we would take care of a few things, viz

  1. We will implement this in all of the 50 modules that are sending SMS’es.
  2. There would be no regression bugs due to this change.

Don’t modify the code that’s already working

Let’s start planning our change. There are two seemingly opposing views here. We don’t want client developers to change their code, not even a single character. At the same time, the SmsClient class we wrote in part IIworks great – and we don’t want to change the code that is already working either.
A little aside – let’s look at the open/closed principle. The open/closed principle tells us that we should not modify existing source code just to add new functionality. Instead, we should find ways to extend it without modifying the source code. It is a part of the SOLID Programming Principles. In fact, it stands for the ‘O’ in the SOLID principles. In our case, the open/closed principle implies that we don’t want to touch the source code for SmsClient.

Using Inheritance

This is a tricky situation, but as with everything else in software, this problem can be solved with a little bit of indirection. We need something sitting in between our clients and our SmsClient class. That something can be a derived class of SmsClient.

# This is the class we wrote in Part III
# We are not allowed to change this class
class SmsClient:
    def send_sms(self, phone_number, message):
        ...
class SmsClientWithRetry(SmsClient):
    def __init__(self, username, password):
        super(SmsClient, self).__init__(username, password)
    def send_sms(self, phone_number, message):
        # TODO: Insert retry logic here
        super(SmsClient, self).send_sms(phone_number, message)
        # TODO: Insert retry logic here
# Earlier, client was an instance of SmsClient, like this
# client = SmsClient(username, password)
# We now change it to be an instance of SmsClientWithRetry
# As a result, our client developers doesn't have to change
# They are simply importing client from sms.py
client = SmsClientWithRetry(username, password)

If you notice, using inheritance, we got ourselves a way to add retry logic without modifying the existing code that is already known to work. This is the crux of the open/closed principle. See Footnotes for a caveat on using inheritance.

Adding Retry Logic

With that done, we can now work on adding the retry logic. We don’t want to retry if our client gave us an invalid phone number or a bad message – because it is a waste of resources. Even if we retried 100 times, it won’t succeed. We also don’t want to retry if there is a logic problem in our module’s code – because our code cannot fix itself magically, and hence, retry is unlikely to help.
In other words, we only want to retry if Watertel has a problem and we believe retrying may end up delivering the message.

If you revisit our original SmsClient implementation, you will now appreciate the way we designed our exceptions. We only want to retry when we get a SmsException. We simply let the client developers deal with all the other exception types.

How do we go about writing the retry loop? The best way to write the retry logic is via a decorator. It’s been done so many times in the past, that it’s best I point you out to some libraries.

Thus, the open/closed principle tells us not to modify our already working code just to add new features. It’s okay to change the code for bug fixes, but other than that, we should look at functional/object-oriented practices to extend the existing code when we want to add new functionalities.
Thus, we saw how the application of the SOLID programming principle and the open/closed principle in specific helped us to manage retries in our system.

A Tip: In general, we should prefer composition over inheritance.

Inheritance versus Composition in Python

We will now compare the inheritance and composition to determine better ways to reuse the existing code.

We now have new requirements for our product managers:

To increase the reliability of our SMSes, we would like to add Milio to our SMS providers. To start with, we want to use Milio only for 20% of the SMSes, the remaining should still be sent via Watertel.
Milio doesn’t have a username/password. Instead, they provide an access token, and we should add the access token as a HTTP header when we make the post request.

Of course, like last time around

  1. We do not want to change existing code that is already working.
  2. We need to have the retry logic for Milio as well.
  3. Finally, we do not want to duplicate any code.

Creating an Interface

The first obvious step is to create a new class MilioClient, with the same interface as our original SmsClient. We have covered this before, so we will just write the pseudo-code below.

class MilioClient:
    def __init__(self, url, access_token):
        self.url = url
        self.access_token = access_token
    def send_sms(self, phone_number, message):
        # Similar to send_sms method in SmsClient
        # Difference would be in the implementation of _make_request
        # We will have different JSON response,
        # and different request parameters
        print("Milio Client: Sending Message '%s' to Phone %s"
                 % (message, phone_number))

Some discussion points –

  1. Should MilioClient extend SmsClient? No. Though both are making network calls, there isn’t much commonality. The request parameters are different, the response format is different.
  2. Should MilioClient extend SmsClientWithRetry? Maybe. Here, the retry logic is reusable and common between the two. We can reuse that logic using inheritance, but it isn’t the right way to reuse. We will discuss this a little later in this post.

Inheritance versus Composition

The reason why we can’t inherit the SmsClientWithRetry class is that the constructor of this class expects a username and password. We don’t have that for Milio. This conflict is large because we made a mistake in the earlier chapter – we chose to build new logic using inheritance. Better late than never. We will refactor our code and this time, we will use Composition instead of Inheritance.

# We rename SmsClient to WatertelSmsClient
# This makes the intent of the class clear
# We don't change anything else in the class
class WatertelSmsClient(object):
    def send_sms(self, phone_number, message):
    ...
# This is our new class to send sms using Milio's APi
class MilioSmsClient(object):
    def send_sms(self, phone_number, message):
    ...
class SmsClientWithRetry(object):
    def __init__(self, sms_client):
        self.delegate = sms_client
    def send_sms(self, phone_number, message):
        # Insert start of retry loop
        self.delegate.send_sms(phone_number, message)
        # Insert end of retry loop
_watertel_client = SmsClient(url, username, password)
# Here, we are passing watertel_client
# But we could pass an object of MilioClient,
# and that would still give us retry behaviour
sms_client = SmsClientWithRetry(_watertel_client)

The logic to Split Traffic

Now let’s look at the next requirement – how do we split the traffic between the two implementations?
The logic is actually simple. Generate a random number between 1 and 100. If it is between 1 and 80, use WatertelSmsClient. If it is between 81 and 100, use MilioSmsClient. Since the number is random, over time we will get an 80/20 split between the implementations.

Introducing a Router class

Now that we have retry logic for Milio in place, let’s face the elephant in the room – where should we put this logic? We cannot change the existing client implementations. And of course, we can’t put this logic in MilioSmsClient or WatertelSmsClient – that logic doesn’t belong there.
The only way out is one more indirection. We create an intermediate class that is used by all existing clients. This class decides to split the logic between MilioSmsClient and WatertelSmsClient. Let’s call this class SmsRouter.

class SmsRouter:
    def send_sms(self, phone_number, message):
        # Generate random number
        # Between 1-80? Call send_sms method in SmsClient
        # Between 80-100? Call send_sms method in MilioClient
        pass

Providing Concrete Implementations to SmsRouter

Our SmsRouter needs instances of SmsClient and MilioClient. The easiest way is for SmsRouter to create the objects in the constructor.

class SmsRouter:
    def __init__(self, milio_url, milio_access_token,
                       watertel_url, watertel_username, watertel_password):
        self.milio = MilioSmsClient(milio_url, milio_access_token)
        self.watertel = WatertelSmsClient(watertel_url, watertel_username, watertel_password)

If you feel the code is ugly, you are not alone. But why is it ugly?
We are passing 6 parameters to the constructor, and are constructing objects in the constructor. If these classes require new parameters, our constructor will also change
To remove this ugliness, we pass fully constructed objects to SmsRouter, like this:

class SmsRouter:
    def __init__(self, milio, watertel):
        self.milio = milio
        self.watertel = watertel

Okay, this is a lot better, but it’s still not great. Our SmsRouter has hard coded percentages for each of the clients. We can do better.

class SmsRouter:
    def __init__(self, milio, milio_percentage, watertel, watertel_percentage):
        self.milio = milio
        self.milio_percentage = milio_percentage
        self.watertel = watertel
        self.watertel_percentage = watertel_percentage

Eeks. We again went up to four parameters. Again, why is this ugly? SmsRouter doesn’t really care about the difference between milio or watertel, but it still has variables with those names.

Generalizing SmsRouter

Let’s generalize it by passing a list of sms providers.

class SmsRouter:
    def __init__(self, providers):
        '''Providers is a list of tuples, each tuple having a provider and a percentage
           providers = [(watertel, 80), (milio, 20)]'''
        self.providers = providers
    def _pick_provider(self):
        # Pick up a provided on the basis of the percentages provided
        # For now, we will pick a random one
        return self.providers[randint(0, 1)][0]
    def send_sms(self, phone_number, message):
        provider = self._pick_provider()
        provider.send_sms(phone_number, message)

With this version of SmsRouter, we can now provide multiple implementations, and the router will intelligently delegate to the right router.

Using our SmsRouter

This is how we can now use the router:

# First, create the concrete implementations
watertel = SmsClient("https://watertel.example.com", "username", "password")
milio = MilioClient("https://milio.example.com", "secret_access_token")
# Create a router with an 80/20 split
sms = SmsRouter([(watertel, 80), (milio, 20)])
# Calling the send_sms in a loop will on an average
# send the messages using the percentages provided
for x in range(1, 10):
    sms.send_sms("99866%s" % (x * 5, ), "Test message %s" % x)

So why composition over inheritance?

Object composition has another effect on system design. Favoring object composition over inheritance helps you keep each class encapsulated and focused on one task. Your classes and class hierarchies will be small and will be less likely to grow into unmanageable monsters.

Also, we were able to add additional functionality without modifying the existing code. This is an example of composition – wrapping existing functionality in powerful ways.

Download E-Book

Harish Thyagarajan
#Business | 6 Min Read
Organizations who proactively see and act upon the opportunities for change through innovation in a highly volatile business environment will not only survive but will also successfully flourish in the toughest of the economic conditions.
Such companies will use innovation as a technological and a strategic tool to develop agile innovation culture and effective business processes.
With companies taking such bold steps, it will enable them to achieve certain key business outcomes such as:

  • Maximizing their Return on Investment to shareholders
  • Effectively achieving business growth goals
  • Increasing the productivity and thereby increasing the profitability
  • Effectively responding to industry disrupters and increasing market share
  • Quickly responding to the external challenges by developing human as well as technological resources to do things differently
Here are some ways to make innovation a strategic tool to transform businesses and for overall sustainability.
It is also a powerful tool that enables people to affect the business breakthroughs and also deliver a profound process, a solid system, and culture.
As a result, there would be increased business engagement, competitiveness, and rapid business growth to enable the business to flourish in this current age of disruption.
Effectively responding to unforeseen events
Being innovate means being willing and competent in knowing how to think and act differently. It is important to know how to think analytically and know how to think at critical levels.
It is also critical to foresee and solve challenges and respond to unprecedented events and external crises in different ways and transform them into creative and innovative solutions that people love and cherish.
Solving complex challenges
One of the main things that one needs to understand about innovation is that it is about how companies perceive and solve challenges in creative ways. There is a need for a sense of urgent passionate purpose to solve complex problems so as to improve the quality of people’s lives and the way we live.
Capitalizing on the global entrepreneurship movement
Currently, the entrepreneurship is a global movement, it is now growing in emerging markets, where countries like China and India are leading the pack. Governments have come to a realization that entrepreneurship is a tool of economic success and have now started backing and supporting entrepreneurs. Innovation enables entrepreneurship and it also empowers people to take complete control of their lives and create their own destiny.
Competing with lean & agile startup methodologies
Every business goes through a rough patch at some point or the other. However, what is really important is making some really effective strategic moves that help in discovering new and unexplored markets.
Lately, many new businesses are slowly shifting towards using certain strategies that incorporate lean as well as agile methodologies as a way of innovating businesses for creating increased value for customers that they value.
Catching up with advances in technology
The advancement of digitization, which is enabled by the IoT has synced the connection and sharing of information between multiple digital devices.
It is because of this connectivity and aggregation of data that more revenue streams are getting created, both for new as well as established firms that leverage existing asset in exciting and profitable ways.
It is also changing the basis of competition as companies will now be able to compete as part of the ecosystems. The increasing availability, as well as accessibility to free and low cost online education, is encouraging and enabling almost everyone with a desire for learning. There is a hunger for knowledge to become subject matter experts in their fields.
Innovative entrepreneurs are expanding their business with the internet of things, fully connected mobile devices, cloud computing and via the social media. Especially by developing software applications that are aimed to improve the quality of people’s lives across the globe.
Adapting to evolving workplace dynamics and trends
At present, millennials are swapping jobs at increasing rates as they seek more meaningful work and equality. Recruitment processes are also shifting as a lot of recruiters are mostly relying on online-based social processes where reputation is becoming extremely important to professionals and organizations.
Freelancing and contracting are also becoming a way of life, a number of people are working from home and taking responsibility for generating own income and wealth.
They are also operating more from coworking and collaborative work environments, which means to say that they are networking as well as teaming up to share and gain knowledge and experience.
These are some of the factors that are forcing companies to explore innovative strategies to enhance staff engagement, empowerment, acquisition and retention of the best resources.
Responding to increasing customer expectations and choices
Major changes are required on how companies perceive their customer’s needs and expectations as they are also empowered by the increasing speed and the wide range of choices available in the strongly connected and digitized world.
Their focus is on getting the value that demonstrates that companies understand as well as empathize with them and even support their lifestyle choices. Increasing consumer expectations, as well as choices, are majorly impacting companies to become more customer-centric via innovative change.
By using human-centered design to improve the user experience, companies can effectively create and invent products and services that people value and cherish.
Maximizing globalization connectivity
Currently, the globalization has been driven by policies. This has opened economies locally and internationally, and as a result, many governments are now adopting free-market economic systems, hugely increasing their own productive potential and creating fresh opportunities for international trade.
They are also reducing the barriers to global trade and bringing in new global agreements for promoting trade in goods, services, and investments.
This trend enables true connectivity as well as collaboration to occur. People are now encouraged to develop an internet-based business that helps them using application of lean methodologies.
People are starting low-cost, online-based businesses because of the increasing availability of private funding and simplification of compliance factors and government infrastructures.
Being highly passionate and having an immense necessity making innovation a strategic and powerful tool to impact business breakthroughs, growth and competitiveness enable companies to prosper in this age of disruption.
Many companies in the future will use innovation as a disruptive mechanism to completely outperform its competitors and venture new markets by enhancing customer experiences.
Pansul Bhatt
#Django | 19 Min Read

This is the seventh post on the Django blog series. In this post we will learn on how we can optimize the django application’s performance. The inspiration of this post has mainly been, the performance improvement of Charcha Discussion Forum. The source code for the charcha forum is available here.

For this post, like all preceding posts in this series, we are going to use Charcha’s codebase as an example and try to optimize the pages from there on out. Also, as the range for optimization is exceedingly high we would try to tackle all the domains one by one. The main focus would be to attain maximum proficiency in the backend (as it is a django application at the end of the day) and the measurement would be done through django debug toolbar

The way we are going to proceed with this is by seeing the performance of the application and see where all can we optimize it domain by domain. To perform the assessment on the site we would be using a bunch of tools, the most important one being django debug toolbar and chrome’s network tab. We are going to hit the front-end portion first and move forward from there.

Optimizing the Front-end:

Typically when you are looking to optimize the application on the front-end we should look for the entire stack to understand how our app is working. This approach should always be followed in all cases as it gives you a better perspective on how things are functioning.

Charcha uses server-side rendering instead of client-side rendering. This on its own solves a lot of problems for us. How?? When performing client-side rendering, your request loads the page markup, its CSS, and its JavaScript. The problem is that all the code is not loaded at once. Instead what happens is JavaScript loads and then makes another request, gets a response and generates the required HTML whereas, with server-side rendering, your initial request loads the page, layout, CSS, JavaScript, and content. So basically, the server does everything for you.

The moment I got to know that Charcha is rendering its template from the server, my focused turned towards looking at only caching and minification of the pages (to be honest this should be present in all applications).

Caching Approach:

Before we start writing any code I want you to understand the working of caching in server-side rendering and how powerful it really is? As you may know, whenever there is an endpoint which returns any data, it can generally be cached. So the main question is that can we cache HTML elements? Yes, by rendering on the server we can easily cache our data.

So what’s going to happen is that the first time your client will get a response and that response will now be cached, so the next time when the same response is made not only will your browser have to do the rendering, your server will also not have to. Now that we have an approach for caching we can start implementing it. In order to perform server-side caching, we are going to use whitenoise Now to integrate whitenoise in our Django app, we just have to follow the following steps:

  • Configuring static files: In Django this isa pretty common approach where you need to add a path of your static files in your settings.py file.
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
  • Enable WhiteNoise: We need to add the whitenoise to our middleware in our settings.py. Do not forget about the hierarchy of your MIDDLEWARE_CLASSES, and whitenoise middleware should be above all middleware’s apart from Django’s SecurityMiddleware.
MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    ...
]

Now whitenoise is going to start serving all your static files but our main purpose for caching is still not done. One thing to note here is that whitenoise also supports compression which we can use.

  • Whitenoise Compression and Caching support: whitenoise has a storage backend which automatically takes care of the compression of the static files and associates each file with a unique identifier so that these files can be cached forever. To exploit this feature all we have to do is add the following lines in our settings.py
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
  • Handling Content Delivery Network: Although we have enabled caching we should still look at CDN to gain maximum efficiency. As whitenoise provides appropriate headers, our CDN can serve the cache files and make sure that for duplicate responses we are not hitting the application again and again, rather serve those request by itself. All we have to do is set an ENV variable as DJANGO_STATIC_HOST and access it in settings.py.
STATIC_HOST = os.environ.get('DJANGO_STATIC_HOST', '')
STATIC_URL = STATIC_HOST + '/static/'
  • WhiteNoise in development: This is one of the main parts as whenever we run the runserver command, django takes over and handles all the static files on its own. So we will not be using whitenoise as effectively as we want to. For using whitenoise what we need to do is disable Django’s static file handling and allow WhiteNoise to take over the handling of all the static files. So we need to edit our settings.pyand add whitenoise.runserver_nostatic immediately above django.contrib.staticfiles.
INSTALLED_APPS = [
    ...
    # Disable Django's own staticfiles handling in favour of WhiteNoise, for
    # greater consistency between gunicorn and `./manage.py runserver`. See:
    # http://whitenoise.evans.io/en/stable/django.html#using-whitenoise-in-development
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',
    ...
]
  • Caching images: There are a few available settings which could be used to configure whitenoise. We are going to try to cache the images for a longer duration of time so as to gain some more performance. For this all we have to do is add awhitenoise header function which would basically look for all the images and cache them for us. So we write something like:
def cache_images_forever(headers, path, url):
    """Force images to be cached forever"""
    tokens = path.split(".")
    if len(tokens) > 1:
        extension = tokens[-1].lower()
        if extension in ('png', 'jpg', 'jpeg', 'ico', 'gif'):
            headers['Cache-Control'] = 'public, max-age=315360000'
WHITENOISE_ADD_HEADERS_FUNCTION = cache_images_forever

Now our caching for the front-end is complete. Let’s move on to the second phase of front-end optimization and try to minify our files.

Minifying the Files:

For minifying our files we are going to use spaceless template tags. Although this will not minify our files per se, it is still going to give us a better result as it would help us reduce our page weight. How?? Well, spaceless template tagsremoves whitespace between HTML tags. This includes tab characters and newlines. This is really easy to implement in Django templates. All we need to add is spaceless and close it with endspacelessin our base.html. As our base.html is going to be used everywhere as the basic skeleton, we can be sure that it will be applied to all the other templates within it as well.

Now that we are done with our front-end optimization let’s move to our back-end. This is perhaps the one place where we would be able to achieve the maximum amount of efficiency.

Optimizing the Back-end:

Ideally, the flow for optimizing your code is to move from your queries to how your Django is functioning. In queries, we need to see the number of queries, the amount of time it takes to execute the query and how our Django ORM’S are working. Internally Django already does a lot for us but we can optimize its queries even further.
We need to start scavenging the code and check the total number of query calls per page. There are a few ways to do this. The most obvious one being logging all the queries in sql.log and start reading the queries from there. There is one other way of accomplishing this, that is by using django debug toolbar.

Now django debug toolbar is a really powerful tool and extremely easy to use. It helps in debugging responses and provides us with a bunch of configurable panels that we could use. We are mainly going to use this to see how quick our queries are and if we are performing any redundant queries.

Django Debug Toolbar

So let’s first integrate the toolbar in Charcha. To install django debug toolbar we are going to follow this doc. Its pretty straightforward and easy to implement. So first we need to install the package using pip.

 $ pip install django-debug-toolbar

One thing to note here is that if you are using a virtualenv avoid using sudo. Ideally we should not be using sudo anyways if we are in a virtualenv. Now our django debug toolbar is installed. We need to now add it in our settings.py INSTALLED_APPS by adding debug_toolbar.

INSTALLED_APPS = [
    ...
    'django.contrib.staticfiles',
    ...
    'debug_toolbar',
    ...
]

Now we need to put the debug toolbar in our middleware. Since there is no preference of the django debug toolbar middleware the middleware stack we can add it wherever we see fit.

MIDDLEWARE = [
    # ...
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    # ...
]

Now we need to add the url to configure the toolbar. We just need to add the url and put it in our DEBUG mode, the rest django debug toolbar will take care of, on its own.

from django.conf import settings
if settings.DEBUG:
    import debug_toolbar
    urlpatterns = [
        url(r'^__debug__/', include(debug_toolbar.urls)),
    ] + urlpatterns

There are also a few configurations that we could use but for now we are going to set it to default as its not required (with the correct version this should be done automatically).

DEBUG_TOOLBAR_PATCH_SETTINGS = False

Also, since we are using our local we need to set the following INTERNAL_IP for django debug toolbar to understand.

INTERNAL_IPS = ('127.0.0.1',)

And now we test. We can now start checking the number of queries that are being run and how much time they are taking to execute as well.

This part is actually a bit easy as all we have to do is set a benchmark on the basis of the amount of data that we have. We also need to consider the higher effect where if we have a lot of data within a lot of foreign keys, we might need to start using indexes there.

To show how we are going to refactor the code we went ahead and started seeing the performance of all the pages. Most refactoring would mostly look at how we could reduce the number of queries.

Now according to the django debug toolbar there are a lot of queries that we are making 8 queries whenever we are making our call to see the post. This would, later on, start giving us problems if we don’t eliminate a few of them. The way we are going to approach optimizing queries is in subparts as follows:

Solving N+1 queries:

We can solve the problem of N+1 queries simply by using prefetch_related and select_related in Charcha. With the two functions, we can have a tremendous performance boost as well. But first, we need to understand what exactly is it that they do and how can we implement it in Charhca.

select_related should be used when the object that you are selecting in a single object of a model, so something like a ForeignKey or a OneToOneField. So whenever you make such a call, select_related would do a join of the two tables and send back the result to you thereby reducing an extra query call to the ForeignKey table.
Let’s see an example to better understand how we can integrate this in Charcha.
We are going to take the example of the Post model which looks something like this:

class Post(Votable):
    ...
    objects = PostsManager()
    title = models.CharField(max_length=120)
    url = models.URLField(blank=True)
    text = models.TextField(blank=True, max_length=8192)
    submission_time = models.DateTimeField(auto_now_add=True)
    num_comments = models.IntegerField(default=0)
    ...

Do note that we have a custom manager defined, so whichever query we need to execute we can define it in our manager. Now in your first glance, you can see that our class Post is inheriting from Votable, so we now need to see what is happening in this class.

class Votable(models.Model):
    ...
    votes = GenericRelation(Vote)
    author = models.ForeignKey(User, on_delete=models.PROTECT)
    ....

Whenever we make a call to check the Author of our Post we will be doing an extra call to the database. So now we go to our custom manager and change the way are fetching the data.

class PostsManager(models.Manager):
    def get_post_with_my_votes(self, post_id, user):
        post = Post.objects\
            .annotate(score=F('upvotes') - F('downvotes'))\
            .get(pk=post_id)
        ...
        return post

If we use the django debug toolbar you would see that whenever we do a call like get_post_with_my_votes().author, we are going to be executing an extra query to the User table.

This is not required and can be rectified easily by using select_related. What do we have to do? Just add select_related to the query.

class PostsManager(models.Manager):
    def get_post_with_my_votes(self, post_id, user):
        post = Post.objects\
            .annotate(score=F('upvotes') - F('downvotes'))\
            .select_related('author').get(pk=post_id)
        ...
        return post

And that’s it. Our redundant query should be removed. Lets check it using django debug toolbar.

We can use prefetch_related when we are going to get a set of things, so basically something like a ManyToManyField or a reverse ForeignKey. How does this help? Well, the way prefetch_related works is it makes another query and therefore reduces the redundant columns in the original object. This as of now is not really required so we are going to let it be.

* Query in a loop:

Though this is not done anywhere in Charcha but this a practise which a lot of people follow without realising its impact. Although this seems pretty basic I still feel that requires its separate section.

post_ids = Post.objects.filter(id = ?).values_list('id', flat=True)
authors = []
for post in post_ids:
    #Disaster as when we would have a lot of post_ids say around 10,000
    #we would be making that many calls, basically (n+1) calls.
    post = Author.objects.filter(id= post_ids)
    authors.append(post)

The above example is just a sample of how disasterous a query in a loop could be for a large dataset and this above example can easily be solved by the previous discussion (on select_related and prefetch_related) which we had.

Denormalization:

I recommend using denormalization only if we have some performance issues and not prematurely start optimizing it. We should check the queries before we start with our denormalization as it does not make any sense if we keep on adding more complexity if it is not impacting our performance.

The best place to explain denormalization implementation in Charcha is in the Votable model as done in the 2nd blog of this series. Why the Votable table? This is because we want to show the score i.e. upvotes – downvotes and the comments on the home page. We could make a join on the Votable table and call it from there but it would slow down our system. Instead what we are doing is, adding the fields of upvotesdownvotes and flag in the Votable model. This would in turn reduce our calls.

class Votable(models.Model):
    ...
    upvotes = models.IntegerField(default=0)
    downvotes = models.IntegerField(default=0)
    flags = models.IntegerField(default=0)
    ...

Now we can just inherit these properties in whichever models we require and from there we can move forward. Although this seems pretty easy to implement it does have a drawback. Every time there is some changes that is made, we would have to update these fields. So instead of making a JOIN we would rather have a more complex UPDATE.

WBS for Tracking Comments Hierarchy

This is also a form of denormalization. Each comment needs a reference to its parent comment and so on , so it basically makes something like the tree structure.

class Comment(Votable):
    ...
    wbs = models.CharField(max_length=30)
    ...

The problem here is that self-referential calls are exceedingly slow. So we can refactor this approach and add a new field called wbs which would help us track the comments as a tree. How would it work? Every comment would have a code, which is a dotted path. So the first comment would have the code “.0001” and the second top-level comment would have the code “.0002” and so on. Now if someone responds to the first comment it gets a code of “.0001.0001”. This would help us avoid doing self-referential queries and use wbs instead.

Now the limitation for this field is we would only allow 9999 comments at each level and the height of the wbs tree would only go till 6, which is sort of acceptable in our case. But in the case of having to go through a large database, we would have to index this field as well. We would discuss this in the next section.

Adding Indexes

Indexes is one of the many standard DB optimization techniques and django provides us with a lot of tools to add these indexes. Once we have identified which all queries are taking a long time we can use Field.db_index or Meta.index_together to add these from Django.

Before we start adding indexes we need to identify where all should we add these properly and to do that we will use django debug toolbar to see how fast we get our response. Now we are going to look at the post which we had before and we are going to track its queries. We are going to select a query which we could easily optimize indexes

SELECT ••• FROM "votes" WHERE ("votes"."type_of_vote" IN ('1', '2') AND "votes"."voter_id" = '2' AND "votes"."content_type_id" = '7' AND "votes"."object_id" = '1')

Now, this particular query is taking 1.45s to execute. Now, all we have to see is the table and which field we could add the index on. Since this query belongs to model Votes we are going to add the index on content_type_id and object_id. How?

class Vote(models.Model):
    class Meta:
        db_table = "votes"
        index_together = [
            ["content_type", "object_id"],
        ]

And that’s all we have to do. Now we run our migrations and check our performance.

Now, this query is taking only 0.4 seconds to execute and that is how easy it is to implement indexes.

Django QuerySets are LAZY

One thing to note when using django is that django querysets are lazy , what that means is queryset does not do any database activity and django will only run the query when the queryset is evaluated. So if we make a call from the Post model like

q = Post.objects.filter(...)
q = q.exclude(...)
q = q.filter(...)

This would make three separate queries which is not really required.

Caching sessions

One thing to notice using the django debug toolbar is that almost all the pages have a query made to retrieve the Django session.

The query that we are tackling is given below and since its being used in almost all the places we can simply cache it once and reap the benefits everywhere else.

SELECT ••• FROM "django_session" WHERE ("django_session"."session_key" = '''6z1ywga1kveh58ys87lfbjcp06220z47''' AND "django_session"."expire_date" > '''2017-05-03 10:56:18.957983''')

By default, Django stores the sessions in our database and expects us to occasionally prune out old entries which we would not be doing.

So on each request, we are doing a SQL query to get the session data and another to grab the User object information. This is really not required and we can easily add a cache here to reduce the load on our server. But the question still remains on which store should we use? From a higher operational point of view, introducing a distributed data store like redis is not really required. Instead, we could simply use cookie-based sessions here.

Do note that we would not be using cookie-based sessions for highly secure sites but Charcha does not need to be highly secure.

How do we implement it?

Using cookie-based sessions is very easy to do. We can simply follow the steps given in this link. All we have to do is add the following in our settings.py (or common.py as per Charcha) and see the magic happen. We will switch to storing our sessions in our cache and easily remove a SQL query from every single request to our site.

SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"

Summary

In this post, we have discussed how one should proceed when optimizing their site. We have tackled all the domains, discussed the various techniques to optimize a Django site and talked about the tools like which django debug toolbar can be used for a sites assessment.

Aman Raj
#Django | 11 Min Read
With, Progressive Web Applications (PWAs), developers can deliver amazing app-like experiences to users using modern web technologies. It is an emerging technology designed to deliver functionalities like push notifications, working offline etc to deliver a rich mobile experience.In this post, we will learn how to make your Django application progressive that works offline.
What are progressive web applications?
Progressive web applications are web applications with the rich user experience. They make smooth user interaction with web and have the following features :
  1. Progressive – Works for any user independent of browser choice.
  2. Instant Loading – Loads instantly without displaying those annoying loading icons.
  3. Fast – Responds quickly to the user request without making the user wait forever.
  4. Connectivity Independent – Work offline or on low-quality networks. Either displays a proper offline message or cached data.
A force that drives progressive web applications
The core concept behind progressive web app is service worker. Service worker is a script which browser runs in the background without interfering with the user’s interaction with the application. Some of the work done by this script include push notification, content caching, data synch when the internet connection is available.
There are a lot more about progressive web applications. But in this post, we are more concerned with connectivity independent feature. We will learn how service workers help us to get the things done. This post is going to be about making a Django application work offline. We will use charcha as our reference application.
Let’s get started without any further delay.
Register a service worker
To bring service worker in the loop, we need to register it in our application. Basically, it tells the browser where it needs to look for the service worker script. Put the following code snippet in your javascript file, it gets loaded as soon as your application runs.
var serviceWorkerPath = "/charcha-serviceworker.js";
 var charchaServiceWorker = registerServiceWorker(serviceWorkerPath);
 function registerServiceWorker(serviceWorkerPath){
    if('serviceWorker' in navigator){
      navigator.serviceWorker
        .register(serviceWorkerPath)
          .then(
            function(reg){
              console.log('charcha service worker registered');
            }
          ).catch(function(error){
            console.log(error)
          });
    }
 }
How does the above code work?
  • If there is browser support for service worker service worker at location /charcha-serviceworker.js is registered. If your browser doesn’t support service worker, then your web application runs normally as if there was no service worker at all.
  • Path of service worker defines its scope. We have defined charcha-serviceworker.js at / i.e at root domain. That means our service worker will listen for all request which is made at this domain and it’s subdomains.
  • It’s all up to you where you want your service worker’s scope to be. In our case we want each and every request to our application to be intercepted, that’s why we have defined root domain scope for our service worker.
If service worker is not successfully registered, you see something like following error in your console. TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.
Launching your Django application
Now go ahead and launch your Django application. Open the browser console and if you are able to see the above-mentioned error, that means you should be grateful to your browser for having service worker support. Okay! that being said, we encountered this error, which means something is wrong. Reload your application and you will see a detailed error message as mentioned below service worker registration failure
This is because Django could not find anything to render for request /charcha-serviceworker.js.
Our next step is to define a URL path and call a view for this path.
Open url.py file and add this url in url pattern list.
url(r'^charcha-serviceworker(.*.js)$', views.charcha_serviceworker, name='charcha_serviceworker'),
Open views.py and write a view function which responds to a browser’s request at /charcha-serviceworker.js
 def charcha_serviceworker(request, js):
      template = get_template('charcha-serviceworker.js')
      html = template.render()
      return HttpResponse(html, content_type="application/x-javascript")
what we are doing above is, just returning our Charcha-serviceworker.js whenever a request is made to download this file.
  • Create an empty service worker script in the root domain of your application. In our case, we created this file at the project root directory as [PROJECT_ROOT]/charcha-serviceworker.js.
  • Open application settings file and inside TEMPLATES add application root path as DIRS value along with existing templates path. After adding, it should look like
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(PROJECT_ROOT, 'templates'), os.path.join(PROJECT_ROOT, ' '),],
        ...
        ...
    },
]
Notice os.path.join(PROJECT_ROOT, ‘templates’) was existing template path and os.path.join(PROJECT_ROOT, ‘ ‘) was added and hence enabling get_template function to search for script file in the project root directory.
Now re run your application and if you do not see the previous error, that means you are good to go with writing service worker script.
Install the service worker
When a service worker is registered, an install event is triggered the very first time an user visits the application page. This is the place where we cache all the resources needed for our application to work offline.
Open the previously created charcha-serviceworker.js and define a callback function which listens for install event.
var cacheName = 'charcha';
var filesToCache = [
'/',
];
self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(cacheName).then(function(cache) {
      return cache.addAll(filesToCache);
    })
  );
});
Let us see what’s going on here
  1. It adds an eventListener which listens for the install event.
  2. Opens a cache with the name charcha.
  3. Adds an array of files which need to be cached and pass it to cache.addAll() function.
  4. event.waitUntil waits untill the caching promise is resolved or rejected.
  5. Service worker is considered successfully installed only when it caches all the files successfully. If it fails to download and cache even a single file, the installation fails and browser throws away this service worker.
Install occurs only once per service worker unless you update and modify the script. In that case, a fresh new service worker will be created without altering the existing running one. We will discuss it more in a later phase which is update phase of a service worker.
Rerun your application and open chrome dev tools. Open Service Workers pane in the Application panel. You will find your service worker with running status. It will show something like below to make sure that the service worker is successfully installed.
service worker installed
You will see a list of cached file in Cache Storage pane under Cache in same Application panel.
NOTE : We can add all the static resources like css files, image files in the list of files to be cached. But dynamic url like /discuss/{post_id} cannot be defined in this list. So how to cache wildcard urls. We will see it in the next section.
Intercept the request and return cached resources
Since we have installed our service worker , we are ready to roll and return responses from our cached resources. Once the service worker is installed, every new request triggers a ‘fetch’ event. We can write a function which listen for this event and responds with the cached version of the requested resource. Our fetch event listener is going to look like
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});
Through the above code snippet, we are trying to fetch the requested resource from the list of cached reources. If it finds, the resource is returned from the cache, otherwise, we make a network request to fetch the resource and return it.
In the previous section, we saw an issue of caching dynamic urls. Let’s see how we can resolve that inside fetchevent listener. Modify the previous code for fetch event to look like
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        }
        var fetchRequest = event.request.clone();
        return fetch(fetchRequest).then(
          function(response) {
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }
            var responseToCache = response.clone();
            caches.open(cacheName)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });
            return response;
          }
        );
      })
    );
});
Let’s walk through the code to see how it solves the aforementioned issue.
How the code solves the aforementioned issue
  1. Only if the requested resource is available in the cache, a cache hit occurs and resource is returned from cache.
  2. In case the cache hit does not occur with the requested resource (which will be the case with dynamic urls), a fresh fetch request is made to fetch the resource from the network.
  3. If the response is not valid, status is not 200 or response type is not basic, the response is returned because error responses need not to be cached.
  4. In case the response is valid, status is 200 and response type is basic, this response is first saved into a cached list and then returned to the client.
You might wonder why are we clonning request and response. Basically, a web request/response is a stream. It can be consumed by only one. In our code, we are consuming request/response for both caching and calling a fetch event. Once read, the stream is gone and will not be available for next read. In order to get a fresh request/response stream again, we clone the request/response.
Now with the above fetch event listener, we are sure that each and every new requested resource is cached and returned when a request is made. At this stage, we are good to go and test the offline running capability of our application. To test it follow these steps:
  1. Rerun the application and browse through a few pages.
  2. Open chrome dev tools and open Service Workers pane in Application panel.
  3. Enable offline check box. After enabling it, you will see a yellow warning icon. This indicates that your application has gone offline.
  4. Now go and browse through all those pages which you previously visited and were cached. You will be able to access those pages without any network error.
Activate the service worker
When you make even a small change in your service worker, it is detected by your browser and your browser downloads and install it.
The updated service worker is launched along side the existing one. Even if it is sucessfully installed, it waits untill the existing service worker has relinquished it’s control from all the pages. If you open service workers pane in Application panel of chrome dev tools, you see new service worker in the waiting state.
Most common use case of activate callback is cache management. When new service worker takes control over your application, you would want to clear the old cache created by old service worker. To do this take a look at following code
self.addEventListener('activate', function(e) {
  e.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== cacheName) {
          return caches.delete(key);
        }
      }));
    })
  );
});
As mentioned previously, the new service worker doesn’t take control over your application immediately. To force new service worker to take over your application you could do any one of the following.
  1. Click on the skipWaiting on the left side of your waiting service worker. (view it in the above image)
  2. You can add self.skipWaiting() in install event listener. When skipWaiting() is called from a installing service worker, it will skip the waiting state and immediately activate.
Now you can Go Gaga over it because you have managed to make your django application work offline.
Summary
You can make Django web apps work faster, more engaging and also work offline. You just need to have support for sevice worker’s in your target browser.
There is more of a progressive web app and service worker. Hang around because in further posts we will discuss
  • How to cache all the pages of your application without browsing each and every page of your application.
  • How to handle post request in offline django application with push and sync event listeners.
Vishal Sharma
#Django | 5 Min Read
This is the fourth post in the Django Blog Series. In this post, we will go through the implementation of web push notifications for Google Chrome in Django. This post is inspired from the push notifications of Charcha Discussion Forum. You can find the full code for the Charcha forum here.
Web Push Notifications require a service worker to run in the browser through which push notification can be sent. It sends the notification through Firebase Cloud Messaging, enabling applications to interact with the users even while not using the application.
Registering Application on Firebase
To send Web Push Notification to the client, you need to register your application on Firebase Console.
  • Register a new project on Firebase.
  • Go to Settings > Project Settings.
  • Go to Cloud Messaging Tabs.
  • Save the server key and sender id. Sender id will be used while registering service worker on client’s machine and server key will be used to send a push notification. Sender Id will be stored in the manifest.json file and server key will be used to send chrome push notification from the server.
Setting up Service Worker
Create a manifest.json file which will contain information about the application.
{
"name": ,
"gcm_sender_id": 
}
Create a service-worker.js file which will contain the event listeners and configuration for notification. Push Event listener will push the notification to the user when an event is received by Service worker.
// Register event listener for the 'push' event.
self.addEventListener('push', function(event) {
 payload = event.data.text();
 // Keep the service worker alive until the notification is created.
 event.waitUntil(
   // Show a notification with title and use the payload
   // as the body.
   self.registration.showNotification(payload.title, payload.options)
 );
});
Notification click event listener specifies the action that needs to be performed when a notification is clicked.
// Event Listener for notification click
self.addEventListener('notificationclick', function(event) {
 event.notification.close();
 event.waitUntil(
   clients.openWindow()
 );
});
Subscribing or Unsubscribing Users
Create a javascript file which contains the code for subscribing to push notification, adding service worker, asking the user for notification permission and storing the endpoint in the database.
Define the following variables:
var serviceWorkerSrc = "/static/serviceworker.js";
var callhome = function(status) {
  console.log(status);
}
var storage = window.localStorage;
var registration;
Define onPageLoad() which will check and register the service worker. On successful registration of service worker it will call initialiseState() which is defined in the next step. function onPageLoad() { // Do everything if the Browser Supports Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register(serviceWorkerSrc) .then( function(reg) { registration = reg; initialiseState(reg); } ); } // If service worker not supported, show warning to the message box else { callhome("service-worker-not-supported"); } } Define initialiseState() which will check whether notifications are supported by the browser or not. If notifications are supported it will call the subscribe() which is defined in the next step.
// Once the service worker is registered set the initial state
 function initialiseState(reg) {
   // Are Notifications supported in the service worker?
   if (!(reg.showNotification)) {
     callhome("showing-notifications-not-supported-in-browser");
     return;
   }
   // Check the current Notification permission.
   // If its denied, it's a permanent block until the
   // user changes the permission
   if (Notification.permission === 'denied') {
     callhome("notifications-disabled-by-user");
     return;
   }
   // Check if push messaging is supported
   if (!('PushManager' in window)) {
     // Show a message and activate the button
     console.log('push-notifications-not-supported-in-browser');
     return;
   }
   subscribe();
Define subscribe() which tries to subscribe the user to push notification. If subscription does not exist, it will ask the user for notification permission. Once notification permission is granted, it will receive the subscription details which will be sent to postSubscribeObj() for processing. If the user has already subscribed the same subscription details will be returned.
function subscribe() {
   registration.pushManager.getSubscription().then(
       function(existing_subscription) {
         // Check if Subscription is available
         if (existing_subscription) {
           endpoint = existing_subscription.toJSON()['endpoint']
           if (storage.getItem(endpoint) === 'failed') {
             postSubscribeObj('subscribe', existing_subscription);
           }
           return existing_subscription;
         }
         // If not, register one using the
         // registration object we got when
         // we registered the service worker
         registration.pushManager.subscribe({
           userVisibleOnly: true
         }).then(
           function(new_subscription) {
             postSubscribeObj('subscribe', new_subscription);
           }
         );
       }
     )
 }
Define unsubscribe() which will unsubscribe the user from the push notification by deleting the endpoint from the database. It will get the subscription details from the pushManager and send it to postSubscribeObj() to update the subscription status on the server.
 function unsubscribe() {
   navigator.serviceWorker.ready.then(function(existing_reg) {
     // Get the Subscription to unregister
     registration.pushManager.getSubscription()
       .then(
         function(subscription) {
           // Check we have a subscription to unsubscribe
           if (!subscription) {
             return;
           }
           postSubscribeObj('unsubscribe', subscription);
         }
       )
   });
 }
Define postSubscribeObj() which updates the endpoint on the server by making an API call.
function postSubscribeObj(statusType, subscription) {
   // Send the information to the server with fetch API.
   // the type of the request, the name of the user subscribing,
   // and the push subscription endpoint + key the server needs
   // to send push messages
   var subscription = subscription.toJSON();
   // API call to store the endpoint in the database
 }
Call onPageLoad() to initialize the worker status check and update subscription.
nPageLoad();
  • Add above javascript file and manifest.json on the home page where you want to ask notification permission from the user.
  • If the user allows, the push notification will be subscribed and the endpoint can be stored. On successful registration, add an API call to save the notification endpoint which will be used to send web push notification to the user.
Sending Web Push Notification
On successful subscription, an endpoint will be stored which can be used to send a notification to the user. For python, Pywebpush package can be used to send web push notification.
Prerequisite
Pywebpush dependency Explicity add pyelliptic==1.5.7 in requirements file as newer version has some issues. from pywebpush import WebPusher subscription = { "endpoint": endpoint, "keys": { "auth": auth, "p256dh": p256dh } } payload = { "title": title, "options": options or {} } WebPusher(subscription).\ send(json.dumps(payload), {}, ttl, GCM_KEY)
Summary
In this blog, you learned the implementation of web push notifications for Google Chrome in Django. This is how you can set up Web Push Notifications for Chrome. Push Libraries- https://github.com/web-push-libs/
Nagesh Dhope
#Django | 5 Min Read
Imagine an application like JIRA with complex workflow. Building such application needs a support for managing finite state machine.Well, if you are building your application with Django, Django FSM provides you out of the box support for managing finite state machine. Let’s assume that our application has the following workflow for a Task.
The basic model for a Task is as follows:
from django.db import models
class Task(models.Model):
   title = models.CharField(max_length=100, null=False)
   description = models.TextField()
Now, let’s see how can we build this using Django FSM.
Installation Process
$ pip install django-fsm
Or, you can install latest git version
$ pip install -e git://github.com/kmmbvnr/django-fsm.git#egg=django-fsm
Define States and State Field in Model
You have to define an FSMState field. On this field, Django FSM will perform transitions. Define these using FSMField.
from django.db import models
from django_fsm import FSMField
class Task(models.Model):
   title = models.CharField(max_length=100, null=False)
   description = models.TextField()
   state = FSMField()
We defined FSMState field but we didn’t associate any states to that field. We can do that as follows:
from django.db import models
from django_fsm import FSMField
STATES = ('Open', 'In Progress', 'Resolved', 'Re Opened', 'Closed')
STATES = list(zip(STATES, STATES))
class Task(models.Model):
   title = models.CharField(max_length=100, null=False)
   description = models.TextField()
   state = FSMField(default=STATES[0], choices=STATES)
Creating Transitions
Django FSM provides a decorator called transition. Once you decorate the model method with transition decorator, you can call the model method to perform transition on each object of a model.
from django.db import models
from django_fsm import FSMField, transition
STATES = ('Open', 'In Progress', 'Resolved', 'Re Opened', 'Closed')
STATES = list(zip(STATES, STATES))
class Task(models.Model):
   ...
   state = FSMField(default=STATES[0], choices=STATES)
    @transition(field=state, source=['Open', 'Re Opened'], target='In Progress')
    def start(self):
    	"""
         	This method will contain the action that needs to be taken once the
         	state is changed. Such as notifying Users.
         	"""
        pass
    @transition(field=state, source='In Progress', target='Resolved')
    def resolve(self):
        """
         	This method will contain the action that needs to be taken once the
         	state is changed. Such as notifying Users
         	"""
        pass
Source parameter accepts a list of states or an individual state. You can use * for the source, to allow switching to the target from any state. The field parameter accepts both the string attribute name or the actual field instance.
Changing State of Object
To change the state of an object, call the model method which is decorated with transition decorator.
task = Task.objects.get(pk=task_id)
task.start()
If start() gets executed successfully without raising any exceptions, state of task object will get updated but it will not be saved into a database. Call save() method to save the object in the database.
task.save()
Adding Conditions on Transitions
There might be situations wherein you want a check of the certain condition prior to performing the transition. You do so in Django FSM using Conditions parameter of transition decorator. Conditions must be a list of functions taking one argument(model instance). The function/method must return,True or False. A conditioning method can be a normal python function.
def can_close(instance):
   """ Return True or False, depending upon some condition """
   pass
or it can be a model method.
def can_close(self):
   """ Return True or False, depending upon some conditions """
   pass
Use conditions like this:
@transition(field=state, source='Resolved', target='Closed', conditions=[can_close])
def close(self):
   """ This method will contain the action that needs to be taken once the state is changed. """
   pass
Handling Exception in Transition Method
Django FSM provides a way to set a fall-back state in case transition method raises an exception.
@transition(field=state, source='Resolved', target='Closed', on_error='failed')
def close(self):
   """ Some exception could happen here """
   pass
Permission-Based Transition
Transition decorator has permission parameter that can be used to check permission prior to transition taking place. Permission accepts a permission string, or callable that expects instance and user arguments and returns True if the user can perform the transition.
@transition(field=state, source='Resolved', target='Closed', permission='myapp.can_change_task')
def close(self):
   """ This method will contain the action that needs to be taken once state is changed. """
   pass
or
@transition(field=state, source='Resolved', target='Closed',
	 permission=lambda instance, user: not user.has_perm('myapp.can_change_task'))
def close(self):
   """ This method will contain the action that needs to be taken once the state is changed. """
   pass
You can check permission with the has_transition_permission method.
from django_fsm import has_transition_perm
def publish_view(request, task_id):
   task = get_object_or_404(Task, pk=task_id)
   if not has_transition_perm(task.close, request.user):
       raise PermissionDenied
   task.close()
State Transition Diagram
You can generate a state transition diagram based on transition methods. You need the pip install graphviz>=0.4library and add django_fsm to your INSTALLED_APPS
INSTALLED_APPS = (
    ...
    'django_fsm',
    ...
)
Now run following command.
$ ./manage.py graph_transitions -o task_transitions.png myapp.Task
Summary
Django FSM has everything that you need to manage finite state machine in your application. In addition to this if want to perform transitions from admin site use Django-FSM-admin. Also, you can maintain transition logs using Django-FSM-log.
Vaibhav Singh
#Technology | 9 Min Read
In this blog post, we will implement sending out scheduled reports via email to our customers in a Django application using Django and celery.
What is Celery?
We will be using Celery to schedule our reports. Celery is an asynchronous task queue based on distributed message passing. It also supports scheduling of tasks. There are two parts in Celery:
  • Worker – Entity which manages the running of tasks in Celery.
  • Broker – Celery communicates through messages, it is the job if the broker to mediate messages between client and worker. Some of the brokers are RabbitMQ and Redis.
Installing Celery
For Django projects, we will install django-celery which in turn installs celery as a dependency. Run this command to install Django-celery: pip install django-celery
Configuring Celery
Adding Django celery configuration in settings.py:
import djcelery
//Add django celery in install apps
INSTALLED_APPS = [
    ...
    'djcelery',
    //Django based broker
    'kombu.transport.django',
    ...
]
# Celery settings
//Specify which broker you will use, we are using django's broker for development
BROKER_URL = 'django://'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
djcelery.setup_loader()
Assuming this is your project structure, we will create a Celery instance in the project folder called celeryapp.py.
project
└─── project/__init__.py
└─── project/settings.py
└─── project/urls.py
└ manage.py
Define your celery instance in project/project/celeryapp.py
from __future__ import absolute_import
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
from django.conf import settings
app = Celery('project')
# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
app.config_from_object('django.conf:settings')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
Now we need to make sure that celery is loaded when your Django application starts. To ensure this import your celery instance in project/project/init.py
from __future__ import absolute_import, unicode_literals
# This will make sure celery is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ['celery_app']
Creating your reports modules
We will be creating a reporting module which will be customizable by the customer through the Django admin interface.
Defining the models for the scheduled reports
We need the administrator of the app to customize the reports scheduling using cron expressions, to evaluate the cron expressions we are using croniter.
class ScheduledReport(models.Model):
    """
        Contains email subject and cron expression,to evaluate when the email has to be sent
    """
    subject = models.CharField(max_length=200)
    last_run_at = models.DateTimeField(null=True, blank=True)
    next_run_at = models.DateTimeField(null=True, blank=True)
    cron_expression = models.CharField(max_length=200)
    def save(self, *args, **kwargs):
        """
        function to evaluate "next_run_at" using the cron expression, so that it is updated once the report is sent.
        """
        self.last_run_at = datetime.now()
        iter = croniter(self.cron_expression, self.last_run_at)
        self.next_run_at = iter.get_next(datetime)
        super(ScheduledReport, self).save(*args, **kwargs)
    def __unicode__(self):
        return self.subject
class ScheduledReportGroup(models.Model):
    """
        Many to many mapping between reports which will be sent out in a
        scheduled report
    """
    report = models.ForeignKey(Report, related_name='report')
    scheduled_report = models.ForeignKey(ScheduledReport,
                               related_name='relatedscheduledreport')
class ReportRecipient(models.Model):
    """
        Stores all the recipients of the given scheduled report
    """
    email = models.EmailField()
    scheduled_report = models.ForeignKey(ScheduledReport, related_name='reportrecep')
The administrator can schedule the reports from the admin interface by entering a cron expression, based on which the reports will be sent out.
Overriding Django form for validation
We will be creating a custom form so that we can validate that the cron expression entered by the user is valid. We are going to hide the last_run_at and next_run_at from the user as it would be irrelevant to them.
from datetime import datetime
from croniter import croniter
from django.forms import ModelForm, ValidationError
from models import ScheduledReport
class ScheduledReportForm(ModelForm):
    class Meta:
        model = ScheduledReport
        fields = ['subject', 'cron_expression']
        fields = ['subject', 'cron_expression']
        help_texts = {'cron_expression': 'Scheduled time is considered in UTC'}
    def clean(self):
        cleaned_data = super(ScheduledReportForm, self).clean()
        cron_expression = cleaned_data.get("cron_expression")
        try:
            iter = croniter(cron_expression, datetime.now())
        except:
            raise ValidationError("Incorrect cron expression:\
            The information you must include is (in order of appearance):\
            A number (or list of numbers, or range of numbers), m, representing the minute of the hour\
            A number (or list of numbers, or range of numbers), h, representing the hour of the day\
            A number (or list of numbers, or range of numbers), dom, representing the day of the month\
            A number (or list, or range), or name (or list of names), mon, representing the month of the year\
            A number (or list, or range), or name (or list of names), dow, representing the day of the week\
            The asterisks (*) in our entry tell cron that for that unit of time, the job should be run every.\
            Eg. */5 * * * * cron for executing every 5 mins")
        return cleaned_data
Creating an admin interface for the Scheduled Reports
from django.contrib import admin
from django.template.defaultfilters import escape
from django.core.urlresolvers import reverse
from project.models import ScheduledReport, ReportRecipient, ScheduledReportGroup
from forms import ScheduledReportForm
class ReportRecipientAdmin(admin.TabularInline):
    model = ReportRecipient
class ScheduledReportAdmin(admin.ModelAdmin):
    """
        List display for Scheduled reports in Django admin
    """
    model = ScheduledReport
    list_display = ('id', 'get_recipients')
    inlines = [
        ReportRecipientAdmin
    ]
    form = ScheduledReportForm
    def get_recipients(self, model):
        recipients = model.reportrecep.all().values_list('email', flat=True)
        if not recipients:
            return 'No recipients added'
        recipient_list = ''
        for recipient in recipients:
            recipient_list = recipient_list + recipient + ', '
        return recipient_list[:-2]
    get_recipients.short_description = 'Recipients'
    get_recipients.allow_tags = True
class ScheduledReportGroupAdmin(admin.ModelAdmin):
    """
        List display for ScheduledReportGroup Admin
    """
    model = ScheduledReportGroup
    list_display = ('get_scheduled_report_name','get_report_name')
    def get_scheduled_report_name(self, model):
        return model.scheduled_report.subject
    def get_report_name(self, model):
        return model.report.name
    get_scheduled_report_name.short_description = "Scheduled Report Name"
    get_report_name.short_description = "Report Name"
    show_change_link = True
    get_report_name.allow_tags = True
admin.site.register(ScheduledReport, ScheduledReportAdmin)
admin.site.register(ScheduledReportGroup, ScheduledReportGroupAdmin)
Creating your reports email service
Create a file project/project/email_service.py. This module consists of the scheduled reports’ emailing service.
from datetime import datetime, timedelta
from django.core.mail import send_mail
from django.template import Template, Context
from django.http import HttpResponse
from django.conf import settings
from .models import ScheduledReport, ScheduledReportGroup, ReportRecipient
class ScheduledReportConfig(object):
    def __init__(self, scheduled_report):
        """
            Expects a scheduled report object and inititializes
            its own scheduled_report attribute with it
        """
        self.scheduled_report = scheduled_report
    def get_report_config(self):
        """
            Returns the configuration related to a scheduled report, needed
            to populate the email
        """
        return {
                "template_context": self._get_related_reports_data(),
                "recipients": self._get_report_recipients()
                }
    def _get_related_reports_data(self):
        """
            Returns the list of reports data which needs to be sent out in a scheduled report
        """
        //Logic to get the reports data and format it as you need
        pass
    def _get_report_recipients(self):
        """
            Returns the recipient list for a scheduled report
        """
        //Logic to get the recipients for a scheduled report
        pass
def create_email_data(content=None):
    //Generate html for the the email body
    content = '''
            
        
         ''' + str(content) + ''''''
    return content
def send_emails():
        current_time = datetime.utcnow()
        //Get all the reports which have to sent out till the current time.
        scheduled_reports = ScheduledReport.objects.filter(next_run_at__lt = current_time)
        for scheduled_report in scheduled_reports:
            report_config = ScheduledReportConfig(scheduled_report).get_report_config()
            //Specify the template path you want to send out in the email.
            template = Template(create_email_data('path/to/your/email_template.html'))
            //Create your email html using Django's context processor
            report_template = template.render(Context(report_config['template_context']))
            scheduled_report.save()
            if not scheduled_report.subject:
                //Handle exception for subject not provided
            if not report_config['recipients']:
                //Handle exception for recipients not provided
            send_mail(
                scheduled_report.subject, 'Here is the message.',
                settings.EMAIL_HOST_USER, report_config['recipients'],
                fail_silently=False, html_message=report_template
            )
Scheduling your email service
Once our email service is ready, we need to schedule the email service in celery. Create a tasks.py file in project/project. We are using celery’s cron based periodic tasks for scheduling our reports.
from celery.task.schedules import crontab
from celery.decorators import periodic_task
from email_service import send_emails
# this will run every minute, see http://celeryproject.org/docs/reference/celery.task.schedules.html#celery.task.schedules.crontab
@periodic_task(run_every=crontab(hour="*", minute="*", day_of_week="*"))
def trigger_emails():
    send_emails()
We have scheduled to run the email service every minute, you can change it based on your requirements. The celery worker will call the email service every minute and whichever reports are due, will be sent out and, their next_run_at and last_run_at attribute will be updated based on the cron expression.
Getting your service worker up and running
Running your celery worker is as simple as running a Django server, just run the command: python manage.py celery worker –beat –loglevel=info –without-gossip –without-mingle –without-heartbeat Your worker is up and running in the background.   Note: We are using Django’s broker only for development for production, we would need Redis, RabbitMQ or some other broker service which is robust and scalable. Also in production, you would need to run celery as a daemon. Here is the link to the documentation for Daemonization.
Summary
We now have a scheduled reporting module which provides the application’s administrator enough flexibility to schedule reports through Django’s admin interface, by simply specifying the cron expression as to when the report needs to be sent out.