From 33a0862215edeaa7848e625cd0b0777fb4885de1 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Thu, 28 Feb 2008 12:57:10 +0000 Subject: queryset-refactor: Fixed exclude() filtering for the various N-to-many relations. This means we can now do nested SQL queries (since we need nested queries to get the right answer). It requires poking directly at the Query class. Might add support for this through QuerySets later. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7170 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- tests/modeltests/many_to_many/models.py | 5 +++++ tests/regressiontests/queries/models.py | 19 ++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py index 198c95c4d5..e09fd825f8 100644 --- a/tests/modeltests/many_to_many/models.py +++ b/tests/modeltests/many_to_many/models.py @@ -126,6 +126,11 @@ __test__ = {'API_TESTS':""" >>> Publication.objects.filter(article__in=[a1,a2]).distinct() [, , , ] +# Excluding a related item works as you would expect, too (although the SQL +# involved is a little complex). +>>> Article.objects.exclude(publications=p2) +[] + # If we delete a Publication, its Articles won't be able to access it. >>> p1.delete() >>> Publication.objects.all() diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index c95026a54e..50c002d14d 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -322,22 +322,19 @@ Bug #5324 >>> Author.objects.exclude(item__name='one').distinct().order_by('name') [, , ] + +# Excluding across a m2m relation when there is more than one related object +# associated was problematic. +>>> Item.objects.exclude(tags__name='t1').order_by('name') +[, ] +>>> Item.objects.exclude(tags__name='t1').exclude(tags__name='t4') +[] + # Excluding from a relation that cannot be NULL should not use outer joins. >>> query = Item.objects.exclude(creator__in=[a1, a2]).query >>> query.LOUTER not in [x[2][2] for x in query.alias_map.values()] True -# When only one of the joins is nullable (here, the Author -> Item join), we -# should only get outer joins after that point (one, in this case). We also -# show that three tables (so, two joins) are involved. ->>> qs = Report.objects.exclude(creator__item__name='one') ->>> list(qs) -[] ->>> len([x[2][2] for x in qs.query.alias_map.values() if x[2][2] == query.LOUTER]) -1 ->>> len(qs.query.alias_map) -3 - Similarly, when one of the joins cannot possibly, ever, involve NULL values (Author -> ExtraInfo, in the following), it should never be promoted to a left outer join. So hte following query should only involve one "left outer" join (Author -> Item is 0-to-many). >>> qs = Author.objects.filter(id=a1.id).filter(Q(extra__note=n1)|Q(item__note=n3)) >>> len([x[2][2] for x in qs.query.alias_map.values() if x[2][2] == query.LOUTER]) -- cgit v1.3