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 <lucas.wi...@gmail.com> 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 django-users+unsubscr...@googlegroups.com.
> To post to this group, send email to django-users@googlegroups.com.
> 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 django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
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.

Reply via email to