A common pattern that has arisen with expressions is to annotate a Q object to the query without going through the Case/When ceremony.
Model.objects.annotate(boolfield=ExpressionWrapper(Q(field__gte=4), output_field=BooleanField()))
We've tried to discourage this pattern because the Case/When structure is a lot more powerful and correct. Sometimes the power isn't required and users really just want to annotate a boolean expression. Q objects and the WhereNode it resolves to aren't really proper expressions, but they could be. Case/When uses Q objects internally, which is why it's important to test Case/When for any major changes to Q and WhereNode.
Explicit support for Q object annotations should implement an implicit BooleanField as the output_field. I believe this is only required on the WhereNode since that is what is ultimately resolved. Once this happens, the above query becomes a lot nicer.
Model.objects.annotate(boolfield=Q(field__gte=4))
For this to work the following is definitely required:
- Add an
output_field=BooleanField()
to WhereNode
- Add a
resolve_expression()
to WhereNode
(unsure what this should return - requires significant testing with Case/When)
Might be required:
- Add an
output_field=BooleanField()
to Q
Tests:
- Adding a subquery containing a Q annotation to a parent query
- Adding a subquery containing a Case/When annotation to a parent query (if it's not already tested)
- Standard tests that most other annotations already implement
- Nullable fields used in Q annotations
I took a quick look at this and ran into circular import problems when setting
output_field=BooleanField()
or importingExpression
(both fromdjango.db.models
). This will need some careful thought about howWhereNode
andQ
interact.