3 awesome Django 4.1 changes (1 is a logout deprecation you need to know about)

Code Review Doctor
3 min readAug 3, 2022

Django is an open-source web application framework for Python. With Django 4.1 release we get some long-awaited improvements such as async views, async database queries, and a deprecation that will eventually prevent your users logging out unless you change your code accordingly.

Deprecation of logout via GET

Log out is an action that has a side effect on the application’s storage: logging out calls request.session.flush. Generally “unsafe” operations that have some side effect on a dependency like a database or cache should not be performed by GET, but instead by POST, PATCH, PUT, DELETE etc. The reason for not using GET is the side effect can be triggered by simply loading up a web page. Lots of room for abuse and unexpected behavior:

  • Browser might pre-fetch the page to display is on the new tab page. Would want that to flush the session?
  • Troll could hyperlink to the logout page to log users out.

Up until 4.1 Django had no opinion on logging out via GET. However it’s now deprecated.

Practically this means no longer linking your “logout” button to the logout view (which will be a GET request) and instead do something like

{% csrf_token %}
<button formmethod="{% url 'admin:logout' %}" formmethod="post" type="submit">Logout</button>

In case formaction or formmethod are new to you see the docs here.

Asynchronous class-based views

An asynchronous view handler allows you to run a parallel program in which a unit of work can run without being linked to the main application thread. Not only this, but it also notifies the calling thread if it fails, gets completed, or progresses.

Subclasses of View may define asynchronous async defmethod handlers to influence asynchronous code using await:

import asyncio
from django.http import HttpResponse
from django.views import View

class AsyncView(View):
async def get(self, request, *args, **kwargs):
# Perform io-blocking view logic using await.sleep
await asyncio.sleep(1)
return HttpResponse("Hello async world!")

It is necessary in a view-class for all user-defined method handlers to either be all synchronous (using def) or all asynchronous (using async def). If that isn’t the case, and async def declarations are mixed with def, an ImproperlyConfigured exception would raise when as_view()is called.

Django automatically detects async views and run them in an asynchronous context.

Asynchronous queries

Before Django 4.1 while writing async code ORM queries would be unavailable as the database queries were blocking: blocking synchronous code blocked the event loop. Indeed Django would notice and raise a SynchronousOnlyOperation to halt it. This is where asynchronous queries come in!

With asynchronous queries you can do as many queries as you want using Django’s asynchronous query API. Every query that may get blocked such as delete or get has an asynchronous variant that is adelete or aget. When you iterate the results, you can simply use the asynchronous iteration (async for) instead. For instance:

async for entry in Authors.objects.filter(name__startswith=”A”):

Improve your Django code

Code Review Doctor is a code scanning tool that suggests Python and Django fixes right inside your pull request.

Check your GitHub or Bitbucket Pull Requests, scan your entire codebase for free online, or follow us on Twitter.