Re: [Django] #10060: Multiple table annotation failure

82 views
Skip to first unread message

Django

unread,
Oct 2, 2011, 6:47:51 PM10/2/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------
Changes (by anonymous):

* ui_ux: => 0
* easy: => 0


Comment:

Another victim. I have a model {{{Foo}}}. I also have models {{{Bar}}} and
{{{Baz}}}, which each have a foreign key pointing to {{{Foo}}} with
related_names {{{'bars'}}}, and {{{'bazs'}}}, respectively:

{{{

for foo in Foo.objects.all().annotate(bar_count=Count('bars'),
baz_count=Count('bazs')):
print foo.bar_count # Was correct
print foo.baz_count # Was completely wrong, but not by any apparent
pattern (ie, the numbers seemed to be almost random)

}}}

I'm unable to display the {{{baz_count}}} in my template now, unless I
want to introduce an N+1 problem (ie, {{{foo.bazs.count()}}} during each
iteration)

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:29>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Oct 11, 2011, 2:49:24 PM10/11/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by anonymous):

Whoa, thought I was doing something wrong in my code until I searched and
found this. Isn't this kind of a big deal? As in, with this bug, isn't
Django's aggregation basically worthless for anyone who's not doing it on
a single table, or did I miss something?

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:30>

Django

unread,
Nov 29, 2011, 9:48:45 AM11/29/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by anonymous):

Is this something that will ever be fixed?

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:31>

Django

unread,
Nov 29, 2011, 1:28:33 PM11/29/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by lukeplant):

Replying to [comment:31 anonymous]:

> Is this something that will ever be fixed?

It will only ever get fixed if someone cares enough to write a patch
(complete with tests). I think at this point a patch which threw an
exception for the failure case would be accepted. Obviously ideally this
would be replaced with a proper fix at some point.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:32>

Django

unread,
Dec 8, 2011, 3:43:42 PM12/8/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by anonymous):

Really, it seems there are plenty of ticket with patches (complete with
tests), and with offers to do the work, but the core team doesn't care.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:33>

Django

unread,
Dec 8, 2011, 3:55:58 PM12/8/11
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by carljm):

Replying to [comment:33 anonymous]:

> Really, it seems there are plenty of ticket with patches (complete with
tests), and with offers to do the work, but the core team doesn't care.

Sorry you're feeling frustrated.

There are currently 15 tickets in Trac marked "Ready for checkin." The
_only_ task in Django's development process that's limited to core
developers is committing those 15 tickets. Fifteen tickets doesn't seem
like such a terrible backlog for an entirely-volunteer crew, frankly.

Any other step in the process (writing a patch, adding tests to an
existing patch, reviewing a patch and marking it "Ready for checkin" if
there are tests, they pass, and it fixes the problem for you) can be done
by anyone in the community. See
https://docs.djangoproject.com/en/dev/internals/contributing/triaging-
tickets/

There is a larger backlog of "design decision needed" tickets (298), but
anyone can contribute usefully to those as well by researching pros and
cons and presenting a balanced summary to the developers mailing list to
start a discussion.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:34>

Django

unread,
Jan 3, 2012, 3:24:02 PM1/3/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by anonymous coward):

It would seem that argumentum ad infinitum is a common theme on here, no?
"A is B", "No, A is A and B is B", "Fine, but C is D..." and so on.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:35>

Django

unread,
Jan 18, 2012, 12:41:40 AM1/18/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: SVN
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------
Changes (by Fak3):

* cc: Fak3 (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:36>

Django

unread,
Nov 16, 2012, 4:06:28 PM11/16/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: master

Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by aaugustin):

#19290 is a duplicate.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:37>

Django

unread,
Nov 25, 2012, 4:51:01 PM11/25/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by michael@…):

Hmm, another victim here. Spent 2 hours trying to understand why my
numbers were so odd to finally find this bug. This is the first time in
several django projects I am really feeling left alone :-(
I am no database expert (which is one reason i LOVE django and it's
awesome Queryset) so I don't see any way that I could provide
implementation help or anything, but seeing that this bug is now open for
several years really makes me shake my head. Even if there is no obvious
fix available, PLEASE at least update the documentatin to point out this
issue!

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:38>

Django

unread,
Nov 25, 2012, 4:58:47 PM11/25/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------
Changes (by michaelB):

* cc: michaelB (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:39>

Django

unread,
Nov 27, 2012, 3:39:15 AM11/27/12
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by akaariai):

This is somewhat hard problem. We could do automatic subquery pushdown for
aggregates - it isn't exactly easy but most of the pieces are already
there. I am not sure how well such queries will perform. Although that
isn't perhaps too important. If the results aren't correct speed doesn't
matter...

I think a good start to this would be documentation + detecting the
problematic situations and throwing an error in those cases. Basically if
we have two multijoins in the query (from filtering, aggregation or
something else) and aggregation is used then the query is likely wrong.
However this condition is a little too restrictive - something like:
{{{
qs.filter(translations__lang='fi', translations__name='foo')
}}}
introduces a multijoin to translations, yet the query is safe as
translations.lang is unique. Detecting if we have a unique multijoin is
going to be nasty. So, we need a way to bypass this error checking.

Proposal: aggregates get a new kwarg "inline" - default False. If inline
is False, then multiple multijoins in single query will raise an error. If
it is True, the aggregate is forced to be joined to the query (that is, to
do what aggregates do today). Later on we will likely add another kwarg
"subquery" - defaults again to False. If set to True the aggregate is
forced to subquery (something like in comment:9). We could also add kwarg
"subselect". Later on maybe also "lateral_subquery" and so on.

The proposal allows us to throw an error, yet give users the ability to
force the ORM to generate the queries they are using now. It also allows
for extending the same API if we get subquery aggregate support some day.

I think we need to add the information about multijoins to JoinInfo, and
add the info about used joins to aggregates when they are added to the
query. Then at compiler stage, check for all inline=False aggregates if
there are multijoins in the query not used by the aggregate itself. If so,
throw an error. Changes should be needed at query.setup_joins(),
compiler.get_from_clause() and then a way to annotate the used joins into
the aggregate (this should not be too hard).

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:40>

Django

unread,
Jan 28, 2013, 2:08:41 PM1/28/13
to django-...@googlegroups.com
#10060: Multiple table annotation failure
---------------------------------+------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: ORM aggregation | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------

Comment (by anonymous):

At this point the documentation on annotations can be considered to be
intentionally misleading.

It is hard not to think this given the severity of the issue and the
comments above.

Yes a code fix is hard but at least an obviously tentative documentation
"fix" can be pushed fairly easily.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:41>

Django

unread,
Aug 14, 2013, 12:40:15 PM8/14/13
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------

Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by anonymous):

Bump

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:43>

Django

unread,
Jun 14, 2014, 8:36:45 AM6/14/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by anonymous):

bump!!!!

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:44>

Django

unread,
Jun 14, 2014, 9:51:08 AM6/14/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by timo):

Bumping this ticket accomplishes nothing. If you want to see it addressed,
please write a patch.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:45>

Django

unread,
Nov 30, 2014, 6:05:47 PM11/30/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by benjaoming):

Agreed with anonymous 01/28/2013 that there needs to be at least some
documentation on this: https://github.com/django/django/pull/3654

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:46>

Django

unread,
Dec 3, 2014, 7:19:23 PM12/3/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"4b23a6c7a9232cc07ec95fe98be17efbd4449822"]:
{{{
#!CommitTicketReference repository=""
revision="4b23a6c7a9232cc07ec95fe98be17efbd4449822"
Documented a current limitation of multiple table annotation; refs #10060.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:47>

Django

unread,
Dec 3, 2014, 7:19:43 PM12/3/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"48bd44670b4c58735d5cdf6762d6b61219ecbb12"]:
{{{
#!CommitTicketReference repository=""
revision="48bd44670b4c58735d5cdf6762d6b61219ecbb12"
[1.7.x] Documented a current limitation of multiple table annotation; refs
#10060.

Backport of 4b23a6c7a9232cc07ec95fe98be17efbd4449822 from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:48>

Django

unread,
Dec 3, 2014, 7:19:55 PM12/3/14
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"a87ade7e30c80de93ec7ad8335d8714b494a58fb"]:
{{{
#!CommitTicketReference repository=""
revision="a87ade7e30c80de93ec7ad8335d8714b494a58fb"
[1.6.x] Documented a current limitation of multiple table annotation; refs
#10060.

Backport of 4b23a6c7a9232cc07ec95fe98be17efbd4449822 from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:49>

Django

unread,
Mar 23, 2015, 12:47:59 PM3/23/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by camillobruni):

I recently ran into a similar problem. The deep joining causes an
explosion of values possibly resulting in many duplicate values. I fixed
this in https://github.com/django/django/pull/4388 by implementing the
DISTINCT parameter on the Aggregate functions. Hence you can do
{{{Sum('center__client__loan__payment_schedule__payments__principal',
distinct=True)}}}
which ignores the duplicate entries.

It might be that the issue at hand is slightly different, but this solves
at least one particular case.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:50>

Django

unread,
Mar 25, 2015, 9:40:56 AM3/25/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by camillobruni):

Replying to [comment:50 camillobruni]:


> I recently ran into a similar problem. The deep joining causes an
explosion of values possibly resulting in many duplicate values. I fixed
this in https://github.com/django/django/pull/4388 by implementing the
DISTINCT parameter on the Aggregate functions. Hence you can do
> {{{Sum('center__client__loan__payment_schedule__payments__principal',
distinct=True)}}}
> which ignores the duplicate entries.
>
> It might be that the issue at hand is slightly different, but this
solves at least one particular case.

Sorry for the noise, I was wrong (in hindsight: "obviously")
http://www.sqlteam.com/article/how-to-use-group-by-with-distinct-
aggregates-and-derived-tables describes the problem I thought of dealing
with in more detail.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:51>

Django

unread,
Jul 13, 2015, 5:23:22 AM7/13/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by glic3rinu):

* cc: glic3rinu (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:52>

Django

unread,
Dec 8, 2015, 5:30:51 PM12/8/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by timgraham):

If I understood Anssi correctly, the existing documentation warning
[https://groups.google.com/d/msg/django-
developers/qiYKd1YZY_E/Tgn0p1wHCQAJ isn't correct], so I submitted
[https://github.com/django/django/pull/5795 a revision].

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:53>

Django

unread,
Dec 15, 2015, 8:04:49 AM12/15/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"3d2236773ba88e330841b8c72183b0e978e10909" 3d22367]:
{{{
#!CommitTicketReference repository=""
revision="3d2236773ba88e330841b8c72183b0e978e10909"
Refs #10060 -- Corrected description of multiple annotations bug.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:54>

Django

unread,
Dec 15, 2015, 8:05:06 AM12/15/15
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"ea63cf8d424780aed35e9973bf5e4dbb652c7d8a" ea63cf8d]:
{{{
#!CommitTicketReference repository=""
revision="ea63cf8d424780aed35e9973bf5e4dbb652c7d8a"
[1.9.x] Refs #10060 -- Corrected description of multiple annotations bug.

Backport of 3d2236773ba88e330841b8c72183b0e978e10909 from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:55>

Django

unread,
Mar 7, 2016, 5:15:01 AM3/7/16
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by tomaszn):

* cc: nowak2000@… (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:56>

Django

unread,
May 6, 2016, 4:15:47 PM5/6/16
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by powderflask):

Replying to [comment:9 bendavis78]:
In [comment:16 comment16] bendavis78 recommends this query to solve the
issue:
> {{{
> #!sql
> SELECT
> u.email,
> (SELECT SUM(points) FROM point_earning WHERE user_id=u.id) AS
points_earned,
> (SELECT SUM(points) FROM point_expense WHERE user_id=u.id) AS
points_spent
> FROM
> "user" u
> }}}

For others who might arrive here looking for a reasonable way to work
around this issue, the following worked well for me. I added a custom
Queryset method to the Manager class, and used a
[https://docs.djangoproject.com/en/1.9/ref/models/expressions/#raw-sql-
expressions RawSQL()] expression to create the annotations. This at
least encapsulates the SQL code and allows the annotation to be integrated
with a normal django queryset. Here's a sample for the example given
above:

{{{
#!python
def annotate_sum_for_user(user_related_modelClass, field_name,
annotation_name):
raw_query = """
SELECT SUM({field}) FROM {model} AS model
WHERE model.user_id = user.id
""".format(
field = field_name,
model = user_related_modelClass._meta.db_table,
)

annotation = {annotation_name: RawSQL(raw_query, [])}
return self.annotate(**annotation)
}}}

Usage for above query on presumed User model:
{{{
#!python
users = models.User.objects\
.annotate_sum_for_user(PointEarning, 'points', 'points_earned')\
.annotate_sum_for_user(PointExpense, 'points', 'points_spent')
}}}

Hope someone finds this useful, and a word of HUGE thanks to those who
worked to get a statement of this issue and a link to this thread into the
django documentation -- probably saved me hours.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:57>

Django

unread,
Jul 17, 2016, 5:34:48 AM7/17/16
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by SonOfLilit):

I just ran into this and submitted a duplicate bug (#26898).

I see a lot of sadness in this thread, joining my own.

My offer to fix if someone knowledgeable about the code can mentor me
still stands. I assume at least detecting it and generating a warning
shouldn't be too hard?

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:58>

Django

unread,
Aug 27, 2016, 6:31:48 PM8/27/16
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner:
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by daniloakamine):

The solution proposed by '''powderflask''' is very interesting and worked
well.
This ticket helped me a lot to understand the big problem.

Thank you all, guys.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:59>

Django

unread,
Nov 16, 2016, 11:11:27 AM11/16/16
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)

Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by akermen):

No sure this will work for all different cases, at least it worked well
for me and the below simplified test case:

Model definitions of test case,
{{{
class ModelA(models.Model):
title = models.CharField(max_length=255, blank=False, null=False,
unique=True)

class ModelB(models.Model):
parent = models.ForeignKey(ModelA, on_delete=models.CASCADE)
value = models.IntegerField()

class ModelC(models.Model):
parent = models.ForeignKey(ModelA, on_delete=models.CASCADE)
}}}

and sample data:
{{{
instance_a_1 = ModelA(title="instance1")
instance_a_1.save()
instance_b = ModelB(parent=instance_a_1, value=1)
instance_b.save()
instance_b = ModelB(parent=instance_a_1, value=3)
instance_b.save()
instance_b = ModelB(parent=instance_a_1, value=5)
instance_b.save()
instance_c = ModelC(parent=instance_a_1)
instance_c.save()
instance_c = ModelC(parent=instance_a_1)
instance_c.save()
instance_c = ModelC(parent=instance_a_1)
instance_c.save()
instance_c = ModelC(parent=instance_a_1)
instance_c.save()
instance_c = ModelC(parent=instance_a_1)
instance_c.save()

instance_a_2 = ModelA(title="instance2")
instance_a_2.save()
instance_b = ModelB(parent=instance_a_2, value=7)
instance_b.save()
instance_b = ModelB(parent=instance_a_2, value=11)
instance_b.save()
instance_c = ModelC(parent=instance_a_2)
instance_c.save()
instance_c = ModelC(parent=instance_a_2)
instance_c.save()
instance_c = ModelC(parent=instance_a_2)
instance_c.save()
}}}

Trying to get two independent annotations from two different tables (sum
of values from ModelB and number of ModelC instances per ModelA instance):
{{{
for a in ModelA.objects.all() \
.annotate(sumB=Sum('modelb__value')) \
.annotate(countC=Count('modelc', distinct=True)):
print "%s: sumB: %s countC: %s" % (a.title, a.sumB, a.countC)
}}}

we get these results
{{{
instance1: sumB: 45 countC: 5
instance2: sumB: 54 countC: 3
}}}

instead of these:
{{{
instance1 sumB: 9 countC: 5
instance2 sumB: 18 countC: 3
}}}
no surprise until here.

As you can see the 'sumB' values are repeated (multiplied) by a factor,
lets account that factor inside single query:
{{{
for a in ModelA.objects.all() \
.annotate(countC=Count('modelc', distinct=True)) \
.annotate(countB=Count('modelb')) \
.annotate(countB_distinct=Count('modelb', distinct=True)) \
.annotate(sumB_multiplied=Sum('modelb__value')) \
.annotate(sumB=(F('sumB_multiplied') * F('countB_distinct')) /
F('countB')):
print "%s sumB: %s countC: %s" % (a.title, a.sumB, a.countC)
}}}

and get correct values:
{{{
instance1 sumB: 9 countC: 5
instance2 sumB: 18 countC: 3
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:60>

Django

unread,
Jul 4, 2017, 2:41:37 PM7/4/17
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Artem.Bernatskyy):

Just have spent 5 hours debugging this bug.

+1

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:61>

Django

unread,
Sep 29, 2017, 1:55:41 AM9/29/17
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Maxim):

* cc: Maxim (added)


Comment:

I think a note about this "feature" in the docs would be helpful.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:62>

Django

unread,
Jan 21, 2018, 2:04:25 PM1/21/18
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by th0th):

* cc: th0th (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:63>

Django

unread,
Feb 4, 2018, 7:39:05 AM2/4/18
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Israel Saeta Pérez):

FTR: See a workaround using `SubQuery` for the issue with annotate
described in this ticket, in this SO post:
https://stackoverflow.com/questions/48598245/multiple-annotate-with-sum-
and-display-data-in-admin-django

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:64>

Django

unread,
May 24, 2018, 4:38:27 PM5/24/18
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Adam M. Costello):

* cc: Adam M. Costello (added)


Comment:

Does anyone here understand roughly what is safe to do with annotate()?

If I call annotate() only once on a queryset, with only one argument, is
that always safe, no matter how many relationships I follow in annotate()
and filter()?

Is it safe to pass multiple arguments to annotate() (or call annotate()
multiple times) if none of the annotations follow any relationships? Even
if there are relationships followed inside filter()?

Do the problems with annotate() also apply to aggregate(), or is it safe
to pass multiple arguments to aggregate() ? Is it safe to call annotate()
with one argument and then call aggregate()?

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:65>

Django

unread,
Dec 5, 2018, 7:06:41 AM12/5/18
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Simon Charette):

Since this ticket has more exposure I wanted to mention that #28296 ought
to fix this by allowing a `subquery` argument to be passed to aggregate
functions.

If it was to be implemented the original report queryset could be made to
return the correct results easily

{{{#!python
Branch.objects.annotate(
total=Sum('center__client__loan__amount'),
repaid=Sum('center__client__loan__payment_schedule__payments__principal',
subquery=True),
)
}}}

Once this lands the ORM should be in a position to detect and warn about
or even deprecate multiple cross joined annotations.

Given the current existing logic with the `Subquery` expression it
shouldn't be too hard for someone with basic expression knowledge about
the ORM to implement a patch if anyone is interested in contributing.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:66>

Django

unread,
Mar 22, 2019, 11:51:26 AM3/22/19
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by wilhelmhb):

Replying to [comment:57 powderflask]:
A huge thanks to powderflask: for the ones knowledgeable enough with SQL,
this is the way to go =)

I also tried the solution described here:
[https://stackoverflow.com/questions/48598245/multiple-annotate-with-sum-
and-display-data-in-admin-django/48607830#48607830], alas without
success...

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:67>

Django

unread,
Jun 16, 2019, 9:36:34 AM6/16/19
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Antoine):

* cc: Antoine (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:68>

Django

unread,
Jun 17, 2019, 4:09:36 AM6/17/19
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Antoine):

People affected by this issue may find this useful:

https://stackoverflow.com/questions/56567841/django-count-and-sum-
annotations-interfere-with-each-other

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:69>

Django

unread,
Jun 10, 2021, 12:19:03 PM6/10/21
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev

(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Adam Sołtysik):

It's very surprising that aggregations aren't done in subqueries. The
problem arises even with basic, one-field aggregations, when there are
duplicates in the original query. So something like this, with a single
reverse foreign key relation:

{{{
User.objects.filter(orders__date=today).distinct().values('first_name').annotate(Count('pk'))
}}}

may produce wrong results (will count orders instead of users), even
though it looks safe with `.distinct()`. From what I've found, the
documentation doesn't warn about such cases.

Funnily enough, when I have rewritten one of my not working queries with
sum aggregation to use a subquery, it actually became faster (on a table
with ~100k rows), but of course YMMV.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:70>

Django

unread,
Oct 18, 2021, 4:42:37 PM10/18/21
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Matthijs Kooijman):

For anyone else running into this, a reasonable workaround seems to be to
use subqueries for aggregating annotations. This is a bit verbose/hacky in
Django currently, as shown by the multitude of approaches in the
stackoverflow link from [[comment:69|Antoine's comment]]. However, I've
successfully used the [[https://github.com/martsberger/django-sql-utils
|django-sql-utils]] package for this just now. That sounds a bit bulky,
but it just has two utilities, one of which is a `SubqueryAggregate` class
(with derived `SubqueryCount`, `SubquerySum`, etc.) that make converting a
regular joining aggregate into a subquery aggregate easy and concise,
without changing the structure much.

For example taking the example from [[comment:66|comment 66]] and
converting the second annotation to a subquery with django-sql-utils,
you'd get:

{{{
Branch.objects.annotate(
total=Sum('center__client__loan__amount'),
repaid=SubquerySum('center__client__loan__payment_schedule__payments__principal'),
)
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:71>

Django

unread,
Dec 1, 2022, 10:11:37 PM12/1/22
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by David Kwong):

* cc: David Kwong (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:72>

Django

unread,
Jul 28, 2023, 10:50:41 AM7/28/23
to django-...@googlegroups.com
#10060: Multiple table annotation failure
-------------------------------------+-------------------------------------
Reporter: svsharma@… | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Natalia Bidart):

#34728 is a (fairly) duplicate of this one.

--
Ticket URL: <https://code.djangoproject.com/ticket/10060#comment:73>

Reply all
Reply to author
Forward
0 new messages