Opened 5 years ago

Last modified 6 weeks 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 aaugustin)

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 aaugustin

  • Description modified (diff)
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

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

comment:3 Changed 5 years ago by carljm

  • Triage Stage changed from Unreviewed to Accepted

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 weeks ago by bmispelon

For reference, it seems that the current behavior is tested (if not documented):

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 weeks ago by morganwahl

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 weeks ago by morganwahl

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