I didn't read closely enough to completely understand but i'll mention that Q object behavior is one of the trickiest bits of the ORM. Some of the relevant reading might be:
* https://github.com/django/django/pull/4385 * https://github.com/django/django/pull/6005 Anssi would be the person to talk to if you want to help out with any improvements. On Saturday, February 13, 2016 at 5:48:25 PM UTC-5, Lucas Wiman 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/38034233-dffb-4e2f-9b2b-d059bc40dbd1%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.