assert test_obj not in TestObj.objects.filter(Q(m2ms__int_value=10) & Q(m2ms__char_value='bar'))
Why shouldn't test_obj be in that query result? test_obj has a m2m with int_value 10 and a m2m (although another one) with char_value bar On Sat, Feb 13, 2016 at 7:45 PM, Lucas Wiman <[email protected]> wrote: > I'm working on the django-predicate library, which defines in-memory > evaluation semantics for Q objects. The eventual goal is to precisely > match the behavior of the ORM on the subset of supported lookup types. > Yesterday, I noticed a bug in that library, where there was a mismatch with > the behavior of the ORM. > > De Morgan's law is a sort of distributive property for Boolean algebras, > stating that (A ∧ B) ⇔ ¬(¬A ∨ ¬B). It has an equivalent statement for > sets and logical predicates. However, it seems Django's Q object does > *not* obey De Morgan's law, which was somewhat surprising. > > I wanted to verify that this intended behavior. If so, does anyone know > where this is documented or Trac tickets that discuss how & and ~ interact > when turned into SQL queries? > > If it is not intended behavior, I'll file a Trac issue about it and we can > continue discussion there. > > Setup of example models.py > > class Base(models.Model): > class Meta: > abstract = True > char_value = models.CharField(max_length=100, default='') > int_value = models.IntegerField(default=0) > date_value = models.DateField(default=datetime.date.today) > datetime_value = models.DateTimeField(default=datetime.datetime.now) > > > class TestObj(Base): > m2ms = models.ManyToManyField( > 'testapp.M2MModel', related_name='test_objs') > > class M2MModel(Base): > pass > > Example > test_obj = TestObj.objects.create() > test_obj.m2ms.create(int_value=10, char_value='foo') > test_obj.m2ms.create(int_value=20, char_value='bar') > > assert test_obj not in TestObj.objects.filter(Q(m2ms__int_value=10) & > Q(m2ms__char_value='bar')) > assert test_obj in TestObj.objects.filter(~(~Q(m2ms__int_value=10) | > ~Q(m2ms__char_value='bar'))) > > If De Morgan's law were obeyed, the two queries would evaluate to the same > result. The generated SQL is recorded in my pull request adding a test > cases reproducing the failure in django-predicate: > https://github.com/ptone/django-predicate/blob/30d23330e71ecc6a8f01743a43a56b406fe764ee/tests/testapp/tests.py#L215-L242 > > The key issue here seems to be crossing an m2m relation, which causes the > negated disjuncts to get evaluated as subqueries. > > Relevant Trac Issues > > https://code.djangoproject.com/ticket/21956 Same issue, but when the > fields occur on the same table that's being queried. This issue was > apparently fixed in Django 1.5. > https://code.djangoproject.com/ticket/13099 > > Thanks, > Lucas > > -- > You received this message because you are subscribed to the Google Groups > "Django users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at https://groups.google.com/group/django-users. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-users/d2f97578-020d-4b7c-9d03-8e3079a18f2f%40googlegroups.com > <https://groups.google.com/d/msgid/django-users/d2f97578-020d-4b7c-9d03-8e3079a18f2f%40googlegroups.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CALn3ei3YirQi-sOEXLh6mFP5d9jkSnR_0hsPbO_1TXOd-4U52w%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.

