Django is probably the best-known Python web framework. We use it pretty much in every project due to its stability, functionalities and ecosystem. Some major changes are being made right now in order to boost the framework with an asynchronous functionality. In this article, we’ll have a look at what to expect from the upgrade.
Django is one of the oldest open-source web frameworks written in Python that are in use to this very day. Throughout its existence, it has undergone numerous changes (built-in migration, end of Python 2 support etc.) – and it is only logical that other modifications are coming with the 3.0 version as well.
The best thing about Django: It is, so to speak, “batteries included”. This means that as soon as you start a project, you already have a wide range of pre-set, ready-to-use functionalities at your disposal.
With other frameworks, a lot of these functionalities need to be created first or selected in another library – this is how the Flask framework works, for instance. Some developers may fancy the close control over functionalities settings, but we strongly prefer the Django approach.
Further advantages of Django are sophisticated documentation and a vast ecosystem of libraries to support the framework. We at Think Easy use Django primarily in combination with the Django REST framework that capitalises on stability and maturity of Django and enables us to build REST API quickly and reliably.
Right now, Django works only synchronously (with the exception of the outstanding Django Channels). This means that when the app executes “I/O bound” actions (such as third-party calling, requesting data from the database etc.), the thread containing the relevant request is “blocked” while waiting for the given action’s response.
Of course, the action can be finished within tens of milliseconds – that is eternity in IT terms, though. So what’s the solution to this problem?
This is where asynchronous programming comes into play. Python allows working with threads as such, which increases the project complexity by an order of magnitude. However, following the approval of several important PEPs (PEP 3156 – asyncio module, PEP 492 – async and await, PEP 380 and others), Python now allows using the so-called coroutines. These make it possible to use the “cooperative concurrency”.
That means all work is still done by one thread only, but the workflow can be paused (such as when waiting for an I/O action) and resumed later. In the meantime, it can do something else.
Thanks to this, the app doesn’t have to stop working and wait for the database response (even if only for a few milliseconds), but can take care of a different task instead – such as handling another request. Once the action communicating with the database is completed (i.e. the database returned the requested data), the relevant request may be processed and a response sent.
Another key term is the “event loop”, which, among other things, enables tracking the states of individual tasks and accepting new tasks.
It might also be helpful to look at the difference between WSGI and ASGI. WSGI defines the difference between web servers and app servers. This interface was specified in 2003 as part of the PEP-333 (PEP-3333 specifies it for Python 3). With this interface, it’s possible to use any web server (such as Nginx) and any app server (such as Gunicorn). However, since WSGI is already a bit of an outdated standard not offering asynchronous functionalities of modern web frameworks, a new standard had to be developed.
This brings us to ASGI. This standard is considered the successor of WSGI. It is compatible with WSGI servers, but at the same time allows for native use of modern protocols (such as WebSockets). The “asgiref” specification now falls under the Django project. The ASGI standard also enables integration of other ASGI apps.
So what does all this mean for Django? Is it necessary to overhaul the whole project to support asynchronous functionality? No, not really. Since Django developers put great emphasis on reverse compatibility (i.e. upgrades don’t affect any functionalities), they opted for a different strategy.
The new asynchronous parts of Django will coexist with those already present. This is why app developers won’t really have to change anything (unless they want to). It will thus be possible to take advantage of the asynchronous functionalities only where it makes sense (such as third-party calling, sending emails directly from the view without the need for an asynchronous queue such as Celery etc.).
The async support was introduced in DEP 0009 (Django Enhancement Proposal; author: Andrew Godwin). It’s divided into 3 stages. In the first stage, the ASGI support is introduced, enabling the use of the app server supporting asynchronous functionalities (such as WebSockets, long polling etc.) – version 3.0. For the next stage, the developers envisage the support of the asynchronous middleware and views – version 3.1.
In the final stage, the asynchronous functionality should be made available for Django ORM (API for communication with the database) – version 3.2/4.0. Andrew Godwin, the leading developer involved in this transition and creator of South, Django Channels, asgiref etc., predicts the third stage to be the most complex one.
In our opinion, the async support is vital for the future of Django. This is simply the path the world of website development is taking. It’s therefore essential that Django doesn’t rest on its laurels and keeps improving. We believe that all those smart people working on this framework are far from being complacent, and that Django remains a relevant framework well into future.