Skip to content

Instantly share code, notes, and snippets.

@bblanchon
Created April 9, 2021 09:03
Show Gist options
  • Select an option

  • Save bblanchon/9e158058fe360e93b1c5d5ce5310015e to your computer and use it in GitHub Desktop.

Select an option

Save bblanchon/9e158058fe360e93b1c5d5ce5310015e to your computer and use it in GitHub Desktop.
Django Subquery Aggregate (Count, Sum...)
from django.db.models import OuterRef
weapons = Weapon.objects.filter(unit__player_id=OuterRef('id'))
units = Unit.objects.filter(player_id=OuterRef('id'))
qs = Player.objects.annotate(weapon_count=SubqueryCount(weapons),
rarity_sum=SubquerySum(units, 'rarity'))
class SubqueryCount(Subquery):
# Custom Count function to just perform simple count on any queryset without grouping.
# https://stackoverflow.com/a/47371514/1164966
template = "(SELECT count(*) FROM (%(subquery)s) _count)"
output_field = PositiveIntegerField()
class SubqueryAggregate(Subquery):
# https://code.djangoproject.com/ticket/10060
template = '(SELECT %(function)s(_agg."%(column)s") FROM (%(subquery)s) _agg)'
def __init__(self, queryset, column, output_field=None, **extra):
if not output_field:
# infer output_field from field type
output_field = queryset.model._meta.get_field(column)
super().__init__(queryset, output_field, column=column, function=self.function, **extra)
class SubquerySum(SubqueryAggregate):
function = 'SUM'
@bblanchon
Copy link
Copy Markdown
Author

@jrobichaud
Copy link
Copy Markdown

Just an observation.

Unlike Sum, default does not work with SubquerySum. Ex: Sum(..., default=0)

Coalesce has to be used instead.

Ex: Coalesce(SubquerySum(units, 'rarity'), 0)

@pauletienney
Copy link
Copy Markdown

Thank you for the gist, it helped me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment