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.
For more options, visit https://groups.google.com/d/optout.