Django 1.11 Goes Live

This version has been designated as a long-term support (LTS) release, which means that security and data loss fixes will be applied for at least the next three years.

What’s new:

This feature allows creating composite and custom indexes for databases. Custom indexes provide better optimization for databases queries and can speed up the response time from databases.

It was an absolute pain to customize the output of the forms. Although at the moment we are simply using API, and this feature seems unnecessary, it still very nice improvement that will facilitate customization of the standard forms. At least we can expect this in django admin.

That’s rather interesting because Django 1.8 introduced conditional expressions for Django ORM. Subquery expressions expand the ORM capabilities. As a result, you can create even more complex things without raw SQL queries.

You can add an explicit subquery to a QuerySet using the Subquery expression.

For example, to annotate each post with the email address of the author of the newest comment on that post:

>>> from django.db.models import OuterRef, Subquery
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
>>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))

On PostgreSQL, the SQL looks like:

SELECT "post"."id", (  
    SELECT U0."email"
    FROM "comment" U0
    WHERE U0."post_id" = ("post"."id")
    ORDER BY U0."created_at" DESC LIMIT 1
) AS "newest_commenter_email" FROM "post"

Referencing columns from the outer queryset

Use OuterRef when a queryset in a Subquery needs to refer to a field from the outer query. It acts like an F expression except that the check to see if it refers to a valid field isn’t made until the outer queryset is resolved.

Instances of OuterRef may be used in conjunction with nested instances of Subquery to refer to a containing queryset that isn’t the immediate parent. For example, this queryset would need to be within a nested pair of Subquery instances to resolve correctly:

>>> Book.objects.filter(author=OuterRef(OuterRef('pk')))

Exists() subqueries

Exists is a Subquery subclass that uses an SQL EXISTS statement. In many cases it will perform better than a subquery since the database is able to stop evaluation of the subquery when a first matching row is found.

For example, to annotate each post with whether or not it has a comment from within the last day:

>>> from django.db.models import Exists, OuterRef
>>> from datetime import timedelta
>>> from django.utils import timezone
>>> one_day_ago = - timedelta(days=1)
>>> recent_comments = Comment.objects.filter(
...     post=OuterRef('pk'),
...     created_at__gte=one_day_ago,
... )
>>> Post.objects.annotate(recent_comment=Exists(recent_comments))

On PostgreSQL, the SQL looks like:

SELECT "post"."id", "post"."published_at", EXISTS(  
    SELECT U0."id", U0."post_id", U0."email", U0."created_at"
    FROM "comment" U0
    WHERE (
        U0."created_at" >= YYYY-MM-DD HH:MM:SS AND
        U0."post_id" = ("post"."id")
) AS "recent_comment" FROM "post"

Previous versions

With the release of Django 1.11, Django 1.10 has reached the end of mainstream support. Django 1.10 will receive security and data loss fixes for another eight months until December 2017.


You are one click away from Django Stars knowledge base