Fixed #7096 -- The simplifications in [7461] weren't complete. They broke

multi-component exclude() calls. Fixed that.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7493 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-04-28 04:29:06 +00:00
parent a1e4b15f15
commit e07a457c00
2 changed files with 30 additions and 6 deletions

View File

@ -895,9 +895,15 @@ class Query(object):
Add a single filter to the query. The 'filter_expr' is a pair: Add a single filter to the query. The 'filter_expr' is a pair:
(filter_string, value). E.g. ('name__contains', 'fred') (filter_string, value). E.g. ('name__contains', 'fred')
If 'negate' is True, this is an exclude() filter. If 'trim' is True, we If 'negate' is True, this is an exclude() filter. It's important to
automatically trim the final join group (used internally when note that this method does not negate anything in the where-clause
constructing nested queries). object when inserting the filter constraints. This is because negated
filters often require multiple calls to add_filter() and the negation
should only happen once. So the caller is responsible for this (the
caller will normally be add_q(), so that as an example).
If 'trim' is True, we automatically trim the final join group (used
internally when constructing nested queries).
If 'can_reuse' is a set, we are processing a component of a If 'can_reuse' is a set, we are processing a component of a
multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse' multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse'
@ -1001,7 +1007,6 @@ class Query(object):
self.where.add((alias, col, field, lookup_type, value), connector) self.where.add((alias, col, field, lookup_type, value), connector)
if negate: if negate:
self.where.negate()
for alias in join_list: for alias in join_list:
self.promote_alias(alias) self.promote_alias(alias)
if final > 1 and lookup_type != 'isnull': if final > 1 and lookup_type != 'isnull':
@ -1039,12 +1044,12 @@ class Query(object):
self.where.start_subtree(connector) self.where.start_subtree(connector)
self.add_q(child, used_aliases) self.add_q(child, used_aliases)
self.where.end_subtree() self.where.end_subtree()
if q_object.negated:
self.where.children[-1].negate()
else: else:
self.add_filter(child, connector, q_object.negated, self.add_filter(child, connector, q_object.negated,
can_reuse=used_aliases) can_reuse=used_aliases)
connector = q_object.connector connector = q_object.connector
if q_object.negated:
self.where.negate()
if subtree: if subtree:
self.where.end_subtree() self.where.end_subtree()

View File

@ -658,5 +658,24 @@ Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
works. works.
>>> Item.objects.values('note__note').order_by('queries_note.note', 'id') >>> Item.objects.values('note__note').order_by('queries_note.note', 'id')
[{'note__note': u'n2'}, {'note__note': u'n3'}, {'note__note': u'n3'}, {'note__note': u'n3'}] [{'note__note': u'n2'}, {'note__note': u'n3'}, {'note__note': u'n3'}, {'note__note': u'n3'}]
Bug #7096 -- Make sure exclude() with multiple conditions continues to work.
>>> Tag.objects.filter(parent=t1, name='t3').order_by('name')
[<Tag: t3>]
>>> Tag.objects.exclude(parent=t1, name='t3').order_by('name')
[<Tag: t1>, <Tag: t2>, <Tag: t4>, <Tag: t5>]
>>> Item.objects.exclude(tags__name='t1', name='one').order_by('name').distinct()
[<Item: four>, <Item: three>, <Item: two>]
>>> Item.objects.filter(name__in=['three', 'four']).exclude(tags__name='t1').order_by('name')
[<Item: four>, <Item: three>]
More twisted cases, involving nested negations.
>>> Item.objects.exclude(~Q(tags__name='t1', name='one'))
[<Item: one>]
>>> Item.objects.filter(~Q(tags__name='t1', name='one'), name='two')
[<Item: two>]
>>> Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two')
[<Item: four>, <Item: one>, <Item: three>]
"""} """}