Skip to main content

Improved API for aggregating using Subquery

Project description

https://travis-ci.org/martsberger/django-sql-utils.svg?branch=master

Django SQL Utils

This package provides utilities for working with Django querysets so that you can generate the SQL that you want, with an API you enjoy.

Subquery Aggregates

The Count aggregation in Django:

Parent.objects.annotate(child_count=Count('child'))

generates SQL like the following:

SELECT parent.*, Count(child.id) as child_count
FROM parent
JOIN child on child.parent_id = parent.id
GROUP BY parent.id

In many cases, this is not as performant as doing the count in a SUBQUERY instead of with a JOIN:

SELECT parent.*,
       (SELECT Count(id)
        FROM child
        WHERE parent_id = parent.id) as child_count
FROM parent

Django allows us to generate this SQL using The Subquery and OuterRef classes:

subquery = Subquery(Child.objects.filter(parent_id=OuterRef('id')).order_by()
                    .values('parent').annotate(count=Count('pk'))
                    .values('count'), output_field=IntegerField())
Parent.objects.annotate(child_count=Coalesce(subquery, 0))

Holy cow! It’s not trivial to figure what everything is doing in the above code and it’s not particularly good for maintenance. SubqueryAggregates allow you to forget all that complexity and generate the subquery count like this:

Parent.objects.annotate(child_count=SubqueryCount('child'))

Phew! Much easier to read and understand. It’s the same API as the original Count just specifying the Subquery version.

In addition to SubqueryCount, this package provides SubqueryMin and SubqueryMax. If you want to use other aggregates, you can use the generic SubqueryAggregate class:

from django.db.models import Avg, DecimalField

aggregate = SubqueryAggregate('child__age', aggregate=Avg,
                               output_field=DecimalField())
Parent.objects.annotate(avg_child_age=aggregate)

Or subclass SubqueryAggregate:

from django.db.models import Avg

class SubqueryAvg(SubqueryAggregate)
    aggregate = Avg
    unordered = True

Parent.objects.annotate(avg_child_age=SubqueryAvg('child__age')

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-sql-utils-0.1.1.tar.gz (6.7 kB view details)

Uploaded Source

Built Distribution

django_sql_utils-0.1.1-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file django-sql-utils-0.1.1.tar.gz.

File metadata

  • Download URL: django-sql-utils-0.1.1.tar.gz
  • Upload date:
  • Size: 6.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2

File hashes

Hashes for django-sql-utils-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e6e6277bc2c89eb617d7e5665b6898d858ed98cdfe09e1bfcaff8c55246da3d6
MD5 0476077fd9186359e8d5458a722d65af
BLAKE2b-256 d05411cc7195efe20b08a862c44594aad6e67e4aa15b0175ee923edcc2a1129d

See more details on using hashes here.

File details

Details for the file django_sql_utils-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: django_sql_utils-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2

File hashes

Hashes for django_sql_utils-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ba11c283977be595bc657581ea450dadf33dada4e66b1447b20f8e23fd94134d
MD5 4622c6028e9c0636c9f77a44ed36e913
BLAKE2b-256 f8dac78747478c9b2a4e2d16ed954bed72d5fcb768bf1314780b4eefcd1abb95

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page