Opened 21 months ago

Closed 21 months ago

Last modified 21 months ago

#34358 closed Bug (fixed)

qs.filter(Exact(expr, value)) doesn’t work on aggregations.

Reported by: Roman Odaisky Owned by: nobody
Component: Database layer (models, ORM) Version: 4.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

class Child(Model):
    parent = ForeignKey(Parent)

a = Parent.objects.filter(Exact(Count("child"), 0)).count()
b = Parent.objects.annotate(n=Count("child")).filter(n=0).count()

Expected: a == b == <number of childless parents>
Actual: a is always 0, b is correct

The two result in different SQL:

-- a:
SELECT COUNT(*) AS "__count"
FROM "parent" LEFT OUTER JOIN "child" ON ("parent"."id" = "child"."report_id")
HAVING COUNT("child"."id") = 0

-- b:
SELECT COUNT(*)
FROM (
    SELECT COUNT("child"."id") AS "n"
    FROM "parent" LEFT OUTER JOIN "child" ON ("parent"."id" = "child"."parent_id")
    GROUP BY "parent"."id"
    HAVING COUNT("child"."id") = 0
)

Am I correct in assuming A should have worked as well?

Change History (3)

comment:1 by Simon Charette, 21 months ago

Resolution: fixed
Status: newclosed

The issue appears to be fixed in Django 4.2 by 59bea9efd2768102fc9d3aedda469502c218e9b7 (#28477) which strips unused annotation.

SELECT COUNT(*)
FROM (
    SELECT "parent"."id"
    FROM "parent"
    LEFT OUTER JOIN "child" ON ("parent"."id" = "child"."parent_id")
    GROUP BY 0
    HAVING COUNT("child"."id") = 0
) subquery

Prior to this change the generate SQL was simply wrong as HAVING cannot be used without a GROUP BY

Please test against 4.2b1 and confirm if your issue is fixed or not.

comment:2 by Mariusz Felisiak, 21 months ago

Summary: qs.filter(Exact(expr, value)) doesn’t workqs.filter(Exact(expr, value)) doesn’t work on aggregations.

comment:3 by Roman Odaisky, 21 months ago

The fix indeed works. Thanks for being proactive!

Note: See TracTickets for help on using tickets.
Back to Top