#32090 closed Cleanup/optimization (invalid)
Negated query on nullable field in conditonal aggregations.
Description ¶
Hello,
The Django ORM adds useless "AND col IS NOT NULL" in negated conditionnal aggregations on non-nullable fields. Here is an example :
class Author(models.Model): name = models.CharField(max_length=100) class Genre(models.IntegerChoices): fantasy = 0, 'Fantasy' horror = 1, 'Horror' scifi = 2, 'Science Fiction' class Book(models.Model): title = models.CharField(max_length=100) author = models.ForeignKey(Author, on_delete=models.CASCADE) genre = models.IntegerField(choices=Genre, null=False)
print(Author.objects.annotate(c=Count('book', filter=~Q(book__genre=Genre.scifi))).query)
SELECT [...], COUNT("book"."id") FILTER (WHERE NOT ("book"."genre" = 2 AND "book"."genre" IS NOT NULL)) AS "c" FROM "author" LEFT OUTER JOIN "book" ON ("author"."id" = "book"."author_id") GROUP BY "author"."id"
The aggregate expression should be, COUNT("book"."id") FILTER (WHERE NOT ("book"."genre" = 2))
.
In the same way that, when building simple filtered query, Django negate correctly the where
clause knowing that genre
is not nullable :
print(Book.objects.filter(~Q(genre=Genre.scifi)).query)
SELECT [...] FROM "book" WHERE NOT ("book"."genre" = 2)
Change History (2)
comment:1 by , 4 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Resolution: | → invalid |
Status: | new → closed |
Summary: | Negated query on nullable field in conditonnal aggregations → Negated query on nullable field in conditonal aggregations. |
Type: | Uncategorized → Cleanup/optimization |
Note:
See TracTickets
for help on using tickets.
These queries are not the same. In the first queryset i.e.
we have a left outer join and a reverse relation. Such relations are always nullable. As a consequence,
book.genre
is also nullable.