Product Design

Feb. 13, 2019

/ code & tools

Django 2.2 - top features software developers are waiting for

Bartek Biskupski

Just a few days ago, community behind Django, well-known and battle-tested Python web framework, announced a beta version of a long-awaited 2.2 release. A stable version is expected to see the daylight in April 2019 so now it's a good moment to estimate an amount of effort needed to update your project. In this article, I’ll briefly guide you through the new features, as well as some backward incompatible changes and deprecations. I’ll also try to help you answer the question whether it’s coming a good moment to switch to a new Django version and how can your application benefit from it.

Say bye to Django 2.0

It’s been already over a year since a breakthrough Django 2.0 was revealed. It’s dropped support for Python 2.7 and simplified syntax of URL routing. An admin panel has been replaced with a responsive one. Same time many features have been removed. In 2018 a lot of developers have welcomed the new release warmly and decided to kick-off new projects on 2.0 codebase. Pablo, one of our colleagues, has dived deeper into Django 2.0 specification, so if you’re looking to migrate from 1.11 or earlier versions it may be worth reading. By the time final release of 2.2 is public prior versions will end its support period (extended support for 2.0 and mainstream support for 2.1). 

Source: Django project

Last call for Python 2.7 migrations

This year you should take into consideration shipping your Python 2.7 codebase to archive and rewriting the application to support one of the recent Python releases. Current LTS (long-term-support) i.e. Django 1.11 is the last one to support Python 2.7. It’ll receive security updates and community support until April 2020. At this point, it’s worth mentioning that new Django LTS is going to be compatible with latest releases of Python 3.5, 3.6 and 3.7, so as you can see 3.4 is going to be abandoned as well.

What’s new in Django 2.2?

New constraints in models

Model’s Meta option is extended by constraints, which allow you adding a limitation to the queries. Namely CheckConstraint and UniqueConstraint classes are added. 

from django.db.models import CheckConstraint, Q
class Customer(models.Model):
    age = models.IntegerField()

    class Meta:
        constraints = [
           CheckConstraint(check=Q(age__gte=18), name='age_gte_18'),

Q object is used to enforce the check. 

When it comes to UniqueConstraint you can ensure uniqueness of the set of fields you provide in a list:  

UniqueConstraint(fields=['room', 'date'], name='unique_reservation')

If you handle a large dataset and your queries are addressed to a certain subset of rows, you may restrict its index by specifying a condition. Again, use Q to specify a condition. 

UniqueConstraint(fields=['customer'], condition=Q(code='DISCOUNT'))

Some other minor changes

As you can see, there are no single major updates in the coming release but there’s a significant amount of small improvements which can boost your productivity with Django. Have a look at how you can enhance your work with models, databases, and others.


  • The request argument was added to the RemoteUserBackend.configure_user() a method as the first positional argument.


  • Oracle support was added for the Envelope function and SpatiaLite support for the covered by and covers lookups.
  • Support for GDAL 1.9 and 1.10 was dropped.


  • The new ordering argument is added to the ArrayAgg and StringAgg classes that specify the ordering of the elements in the results.
  • The new search_type parameter of SearchQuery provides new functionalities for formatting queries in Full Text Search. 
from import SearchQuery

SearchQuery( 'red apple', search_type='phrase')
SearchQuery("'apple' & ('red' | 'green')", search_type='raw')


  • The new setup hook initializes attributes: self.request, self.args, and self.kwargs prior to dispatch(). Overriding this method allows mixins to setup instance attributes for reuse in child classes.


  • The new migrate --plan option returns the list of migration operations to be performed.
  • NoneType can now be serialized in migrations.
  • Custom serializers for migrations can be registered.


  • The new QuerySet.bulk_update() method allows updating specific fields on multiple model instances in an efficient way.
apples = [
      Fruit.objects.create(description='Apple 1'),
      Fruit.objects.create(description='Apple 2'),
apples[0].description = 'Red apple'
apples[1].description = 'Green apple'
Fruit.objects.bulk_update(objs, ['description'])
  • Performance of autocommit is improved by reducing the number of database round trips. A transaction is no longer started when a single query is being performed, such as, QuerySet.update(), and Model.delete(). 
  • DISTINCT aggregation is added to the Aggregate class to ensure that the aggregate function is only called for each distinct value of expressions.
  • The RelatedManager.add(), create(), remove(), set(), get_or_create(), and update_or_create() methods are now allowed on many-to-many relationships.


  • Simple access to headers through HttpRequest.headers was added. 


  • Data can be deserialized using natural keys containing forward references by passing handle_forward_references=True to serializers.deserialize(). 

Backward incompatible updates and deprecations

Changes in Django are not only about adding new features, but some of the code is getting deprecated and may become incompatible with your project. I’ll go briefly through ones which may be most significant for your daily work. For further reading check out the official Django documentation.

Database API

  • Some third-party database backends will require changes including implementing support for checking additional constraints. 


  • Admin actions are no longer collected from base ModelAdmin classes and follow standard Python inheritance.


  • UUIDField form field now displays values with dashes.
  • For consistency with WSGI servers, the test client now sets the Content-Length header to a string instead of an integer.
  • Runserver no longer supports pyinotify. 


  • A common source of confusion, the Meta.ordering affecting queries such as annotate().values() will now receive advice to add .order_by() to retain current query and will be ignored in future versions.

Django revolution? 

As Django is one of the most popular Python frameworks, software developers are looking out for every bigger change and improvement. Django 2.2 might not be revolutionary but it will bring us a stable long-term support release and it batches up lots of new features added since Django 2.0. It’s a perfect moment to scope required updates and schedule bumping up your project codebase. Just keep in mind that beta is not for production use, but you can take some new features for a spin or even help finding some bugs.

Interested in raising your Django knowledge and skills? Join our backend team and work on the great software development projects for clients and the community.  

We use cookies on this site to improve performance. By browsing this site you are agreeing to this. For more information see our Privacy policy.