Opened 5 years ago

Last modified 6 months ago

#16893 new Bug

negation of Q object returns the same thing

Reported by: morgy.wahl@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.2
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Aymeric Augustin)

Not sure if this is a bug.

I was attempt to construct a Q object that wouldn't ever match anything (an API calls for a Q object to be returned, but certain situations call for nothing to be matched by it). I initially figured ~ Q() would do the trick, but that matches everything, just like a plain Q().

(I ended up using Q(pk__isnull=True), which is a hack but seems to be OK.)

Change History (5)

comment:1 Changed 5 years ago by Aymeric Augustin

Description: modified (diff)

Fixed formatting (you can use "preview" before submitting a ticket).

comment:3 Changed 5 years ago by Carl Meyer

Triage Stage: UnreviewedAccepted

Haven't dug into what would be required to make this work, but presuming it can be reasonably implemented this seems sensible.

comment:4 Changed 6 months ago by Baptiste Mispelon

For reference, it seems that the current behavior is tested (if not documented): https://github.com/django/django/blob/master/tests/queries/tests.py#L1692-L1694

Come to think of it, I'm not really sure how empty Q objects should be treated: what's the expected result of filter(Q()), filter(~Q()), exclude(Q()), or exclude(~Q())?

comment:5 Changed 6 months ago by Morgan Wahl

Ah, I see. filter() == all() == exclude(), all of which != none(). Keeping filter(~Q(...)) == exclude(Q(...))) certainly makes sense (if that's possible).

Maybe define a special singleton instance of Q that matches nothing?

comment:6 Changed 6 months ago by Morgan Wahl

To elaborate:

In django.db.models or someplace like it:

Nope = Q(pk__isnull=True)

Then in other code:

from django.db.models import Nope
qs.filter(Nope) == qs.none()
qs.exclude(Nope) == qs.all()

That still uses my pk__isnull=True hack, but that might be fine. Alternatively, the Q class itself could add some kind of explicit support for this.

I think these expressions should all be true: Nope | Q() == Q(), Nope & Q() == Nope, ~Nope == Q()

Nope isn't a great name, but it was the best I could do; Null is confusing with the SQL concept, None is taken, of course, and Nothing sounds like what filter(Nope) would return, not what it's passed. Is there a better word for unmatchable criteria?

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