From 2dd9a85819218e481f9bc6e88264c2b1ae5f25e8 Mon Sep 17 00:00:00 2001
From: Adrian Holovaty <adrian@holovaty.com>
Date: Sat, 9 Jan 2010 21:27:39 +0000
Subject: [PATCH] Fixed #7235 -- EmptyQuerySet no longer raises and exception
 when it's filter()ed (along with some other QuerySet methods). Thanks,
 taylormarshall

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12147 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/db/models/query.py               | 75 +++++++++++++++++++++++++
 tests/regressiontests/queries/models.py | 35 +++++++++++-
 2 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/django/db/models/query.py b/django/db/models/query.py
index 0b57b1e4bc..4e3326a9ca 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1014,6 +1014,81 @@ class EmptyQuerySet(QuerySet):
         # (it raises StopIteration immediately).
         yield iter([]).next()
 
+    def all(self):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def filter(self, *args, **kwargs):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def exclude(self, *args, **kwargs):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def complex_filter(self, filter_obj):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def select_related(self, *fields, **kwargs):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def annotate(self, *args, **kwargs):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def order_by(self, *field_names):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def distinct(self, true_or_false=True):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def extra(self, select=None, where=None, params=None, tables=None,
+              order_by=None, select_params=None):
+        """
+        Always returns EmptyQuerySet.
+        """
+        assert self.query.can_filter(), \
+                "Cannot change a query once a slice has been taken"
+        return self
+
+    def reverse(self):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def defer(self, *fields):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
+    def only(self, *fields):
+        """
+        Always returns EmptyQuerySet.
+        """
+        return self
+
     # EmptyQuerySet is always an empty result in where-clauses (and similar
     # situations).
     value_annotation = False
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index aababffbab..43c843756c 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -8,7 +8,8 @@ import sys
 
 from django.conf import settings
 from django.db import models, DEFAULT_DB_ALIAS
-from django.db.models.query import Q, ITER_CHUNK_SIZE
+from django.db.models import Count
+from django.db.models.query import Q, ITER_CHUNK_SIZE, EmptyQuerySet
 
 # Python 2.3 doesn't have sorted()
 try:
@@ -969,6 +970,38 @@ Bug #7759 -- count should work with a partially read result set.
 ...     break
 True
 
+Bug #7235 -- an EmptyQuerySet should not raise exceptions if it is filtered.
+>>> q = EmptyQuerySet()
+>>> q.all()
+[]
+>>> q.filter(x=10)
+[]
+>>> q.exclude(y=3)
+[]
+>>> q.complex_filter({'pk': 1})
+[]
+>>> q.select_related('spam', 'eggs')
+[]
+>>> q.annotate(Count('eggs'))
+[]
+>>> q.order_by('-pub_date', 'headline')
+[]
+>>> q.distinct()
+[]
+>>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
+[]
+>>> q.query.low_mark = 1
+>>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
+Traceback (most recent call last):
+...
+AssertionError: Cannot change a query once a slice has been taken
+>>> q.reverse()
+[]
+>>> q.defer('spam', 'eggs')
+[]
+>>> q.only('spam', 'eggs')
+[]
+
 Bug #7791 -- there were "issues" when ordering and distinct-ing on fields
 related via ForeignKeys.
 >>> len(Note.objects.order_by('extrainfo__info').distinct())