Querysets are now lest restrictive when querying duplicate fields (#332, #333)

This commit is contained in:
Ross Lawley 2013-06-04 10:46:38 +00:00
parent 985bfd22de
commit ee725354db
3 changed files with 28 additions and 8 deletions

View File

@ -5,6 +5,7 @@ Changelog
Changes in 0.8.2 Changes in 0.8.2
================ ================
- Querysets are now lest restrictive when querying duplicate fields (#332, #333)
- FileField now honouring db_alias (#341) - FileField now honouring db_alias (#341)
- Removed customised __set__ change tracking in ComplexBaseField (#344) - Removed customised __set__ change tracking in ComplexBaseField (#344)
- Removed unused var in _get_changed_fields (#347) - Removed unused var in _get_changed_fields (#347)

View File

@ -26,6 +26,7 @@ class QNodeVisitor(object):
class DuplicateQueryConditionsError(InvalidQueryError): class DuplicateQueryConditionsError(InvalidQueryError):
pass pass
class SimplificationVisitor(QNodeVisitor): class SimplificationVisitor(QNodeVisitor):
"""Simplifies query trees by combinging unnecessary 'and' connection nodes """Simplifies query trees by combinging unnecessary 'and' connection nodes
into a single Q-object. into a single Q-object.
@ -39,6 +40,7 @@ class SimplificationVisitor(QNodeVisitor):
try: try:
return Q(**self._query_conjunction(queries)) return Q(**self._query_conjunction(queries))
except DuplicateQueryConditionsError: except DuplicateQueryConditionsError:
# Cannot be simplified
pass pass
return combination return combination
@ -127,8 +129,7 @@ class QCombination(QNode):
# If the child is a combination of the same type, we can merge its # If the child is a combination of the same type, we can merge its
# children directly into this combinations children # children directly into this combinations children
if isinstance(node, QCombination) and node.operation == operation: if isinstance(node, QCombination) and node.operation == operation:
# self.children += node.children self.children += node.children
self.children.append(node)
else: else:
self.children.append(node) self.children.append(node)

View File

@ -68,9 +68,11 @@ class QTest(unittest.TestCase):
x = IntField() x = IntField()
y = StringField() y = StringField()
# Check than an error is raised when conflicting queries are anded
query = (Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc) query = (Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(query, {'$and': [ {'x': {'$lt': 7}}, {'x': {'$lt': 3}} ]}) self.assertEqual(query, {'$and': [{'x': {'$lt': 7}}, {'x': {'$lt': 3}}]})
query = (Q(y="a") & Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(query, {'$and': [{'y': "a"}, {'x': {'$lt': 7}}, {'x': {'$lt': 3}}]})
# Check normal cases work without an error # Check normal cases work without an error
query = Q(x__lt=7) & Q(x__gt=3) query = Q(x__lt=7) & Q(x__gt=3)
@ -323,10 +325,26 @@ class QTest(unittest.TestCase):
pk = ObjectId() pk = ObjectId()
User(email='example@example.com', pk=pk).save() User(email='example@example.com', pk=pk).save()
self.assertEqual(1, User.objects.filter( self.assertEqual(1, User.objects.filter(Q(email='example@example.com') |
Q(email='example@example.com') | Q(name='John Doe')).limit(2).filter(pk=pk).count())
Q(name='John Doe')
).limit(2).filter(pk=pk).count()) def test_chained_q_or_filtering(self):
class Post(EmbeddedDocument):
name = StringField(required=True)
class Item(Document):
postables = ListField(EmbeddedDocumentField(Post))
Item.drop_collection()
Item(postables=[Post(name="a"), Post(name="b")]).save()
Item(postables=[Post(name="a"), Post(name="c")]).save()
Item(postables=[Post(name="a"), Post(name="b"), Post(name="c")]).save()
self.assertEqual(Item.objects(Q(postables__name="a") & Q(postables__name="b")).count(), 2)
self.assertEqual(Item.objects.filter(postables__name="a").filter(postables__name="b").count(), 2)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()