#32549: Add `Q.empty()` to check for nested empty Q objects like `Q(Q())` -------------------------------------+------------------------------------- Reporter: jonathan-golorry | Owner: nobody Type: | Status: new Cleanup/optimization | Component: Database layer | Version: dev (models, ORM) | Severity: Normal | Resolution: Keywords: Q objects, nested, | Triage Stage: empty | Unreviewed Has patch: 1 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Changes (by jonathan-golorry):
* status: closed => new * resolution: wontfix => Old description: > Empty Q objects (`Q()` or `~Q()`, etc) evaluate to `False`, but `Q(Q())` > evaluates to `True`. This interferes with the shortcut on logical > operations involving empty Q objects and can lead to bugs when trying to > detect empty operations. > {{{ > def q_any(iterable): > q = Q() > for element in iterable: > q |= element > if q: > return q > return Q(pk__in=[]) > Item.objects.filter(q_any()) # no items > Item.objects.filter(q_any([Q()])) # no items > Item.objects.filter(q_any([Q(Q())])) # all items > }}} > > Patch https://github.com/django/django/pull/14127 removes empty Q objects > from `args` during Q object initialization. > > This requires https://code.djangoproject.com/ticket/32548 in order to > prevent a regression in logical operations between query expressions and > empty Q objects. New description: Empty Q objects (`Q()` or `~Q()`, etc) evaluate to `False`, but `Q(Q())` evaluates to `True`. This interferes with the shortcut on logical operations involving empty Q objects and can lead to bugs when trying to detect empty operations. {{{ def q_any(iterable): q = Q() for element in iterable: q |= element if q: return q return Q(pk__in=[]) Item.objects.filter(q_any()) # no items Item.objects.filter(q_any([Q()])) # no items Item.objects.filter(q_any([Q(Q())])) # all items }}} ~~Patch https://github.com/django/django/pull/14127 removes empty Q objects from `args` during Q object initialization.~~ Patch https://github.com/django/django/pull/14130 adds `.empty()` for detecting nested empty Q objects and uses that instead of boolean evaluation for shortcutting logical operations between empty Q objects. So `Q(x=1) | Q(Q())` will now shortcut to `Q(x=1)` the same way `Q(x=1) | Q()` does. No simplifying is done during Q object initialization. This requires https://code.djangoproject.com/ticket/32548 in order to prevent a regression in logical operations between query expressions and empty Q objects. -- Comment: Here is an alternate approach that adds a way to check for nested empty Q objects instead of making them impossible to create. -- Ticket URL: <https://code.djangoproject.com/ticket/32549#comment:3> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/074.0f8410eddd348955e01fb04edf02243c%40djangoproject.com.