Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#20216 closed Bug (invalid)

filtering over an Sum on a BooleanField uses BooleanField's get_db_prep_lookup on the value

Reported by: Anossov Owned by: nobody
Component: Database layer (models, ORM) Version: 1.5
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


With a model like this:

class Test(models.Model):
    active = models.BooleanField()
    group = models.IntegerField()

this queryset:


As well as this one, and one with any other value


Generates this SQL and params

SELECT "test_test"."group", SUM("test_test"."active") AS "s" FROM "test_test" GROUP BY "test_test"."group" HAVING SUM("test_test"."active") > ? LIMIT 21


That is, any value is converted to bool by BooleanField's get_db_prep_lookup called from here.

Change History (3)

comment:1 Changed 2 years ago by aaugustin

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to invalid
  • Status changed from new to closed

In general, aggregation only works when the result of the aggregate has the same type as the original value.

Arithmetic on booleans doesn't make sense, even though Python attemps to perform it:

>>> bool(True - True)
>>> bool(True / False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Specifically, your code won't work on databases where true and false are stored as 't' and 'f'.

comment:2 Changed 2 years ago by Anossov

This is just somewhat inconsistent — the docs say only numeric fields are allowed in Avg, but it is not enforced, and Avg works on BooleanFields because the result is always a FloatField. A mention in the Sum docs or an exception instead of undefined behaviour would be nice.

comment:3 Changed 2 years ago by aaugustin

It's an accident of duck-typing that Avg works on boolean fields, and as said in my first comment, it certainly doesn't work on all databases.

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