mirror of
https://github.com/django/django.git
synced 2025-09-26 12:09:19 +00:00
Fixed #3283 -- Added support for empty QuerySets via none() method. Thanks for the patch, medhat
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4394 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
31bdd8d720
commit
13280259a8
4 changed files with 97 additions and 16 deletions
|
@ -25,6 +25,9 @@ QUERY_TERMS = (
|
|||
# Larger values are slightly faster at the expense of more storage space.
|
||||
GET_ITERATOR_CHUNK_SIZE = 100
|
||||
|
||||
class EmptyResultSet(Exception):
|
||||
pass
|
||||
|
||||
####################
|
||||
# HELPER FUNCTIONS #
|
||||
####################
|
||||
|
@ -168,7 +171,12 @@ class QuerySet(object):
|
|||
extra_select = self._select.items()
|
||||
|
||||
cursor = connection.cursor()
|
||||
select, sql, params = self._get_sql_clause()
|
||||
|
||||
try:
|
||||
select, sql, params = self._get_sql_clause()
|
||||
except EmptyResultSet:
|
||||
raise StopIteration
|
||||
|
||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||
fill_cache = self._select_related
|
||||
index_end = len(self.model._meta.fields)
|
||||
|
@ -192,7 +200,12 @@ class QuerySet(object):
|
|||
counter._offset = None
|
||||
counter._limit = None
|
||||
counter._select_related = False
|
||||
select, sql, params = counter._get_sql_clause()
|
||||
|
||||
try:
|
||||
select, sql, params = counter._get_sql_clause()
|
||||
except EmptyResultSet:
|
||||
return 0
|
||||
|
||||
cursor = connection.cursor()
|
||||
if self._distinct:
|
||||
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
|
||||
|
@ -523,7 +536,12 @@ class ValuesQuerySet(QuerySet):
|
|||
field_names = [f.attname for f in self.model._meta.fields]
|
||||
|
||||
cursor = connection.cursor()
|
||||
select, sql, params = self._get_sql_clause()
|
||||
|
||||
try:
|
||||
select, sql, params = self._get_sql_clause()
|
||||
except EmptyResultSet:
|
||||
raise StopIteration
|
||||
|
||||
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
|
||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||
while 1:
|
||||
|
@ -545,7 +563,12 @@ class DateQuerySet(QuerySet):
|
|||
if self._field.null:
|
||||
self._where.append('%s.%s IS NOT NULL' % \
|
||||
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
|
||||
select, sql, params = self._get_sql_clause()
|
||||
|
||||
try:
|
||||
select, sql, params = self._get_sql_clause()
|
||||
except EmptyResultSet:
|
||||
raise StopIteration
|
||||
|
||||
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
|
||||
(backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
|
||||
backend.quote_name(self._field.column))), sql, self._order)
|
||||
|
@ -562,6 +585,25 @@ class DateQuerySet(QuerySet):
|
|||
c._kind = self._kind
|
||||
c._order = self._order
|
||||
return c
|
||||
|
||||
class EmptyQuerySet(QuerySet):
|
||||
def __init__(self, model=None):
|
||||
super(EmptyQuerySet, self).__init__(model)
|
||||
self._result_cache = []
|
||||
|
||||
def iterator(self):
|
||||
raise StopIteration
|
||||
|
||||
def count(self):
|
||||
return 0
|
||||
|
||||
def delete(self):
|
||||
pass
|
||||
|
||||
def _clone(self, klass=None, **kwargs):
|
||||
c = super(EmptyQuerySet, self)._clone(klass, **kwargs)
|
||||
c._result_cache = []
|
||||
return c
|
||||
|
||||
class QOperator(object):
|
||||
"Base class for QAnd and QOr"
|
||||
|
@ -571,10 +613,14 @@ class QOperator(object):
|
|||
def get_sql(self, opts):
|
||||
joins, where, params = SortedDict(), [], []
|
||||
for val in self.args:
|
||||
joins2, where2, params2 = val.get_sql(opts)
|
||||
joins.update(joins2)
|
||||
where.extend(where2)
|
||||
params.extend(params2)
|
||||
try:
|
||||
joins2, where2, params2 = val.get_sql(opts)
|
||||
joins.update(joins2)
|
||||
where.extend(where2)
|
||||
params.extend(params2)
|
||||
except EmptyResultSet:
|
||||
if not isinstance(self, QOr):
|
||||
raise EmptyResultSet
|
||||
if where:
|
||||
return joins, ['(%s)' % self.operator.join(where)], params
|
||||
return joins, [], params
|
||||
|
@ -628,8 +674,11 @@ class QNot(Q):
|
|||
self.q = q
|
||||
|
||||
def get_sql(self, opts):
|
||||
joins, where, params = self.q.get_sql(opts)
|
||||
where2 = ['(NOT (%s))' % " AND ".join(where)]
|
||||
try:
|
||||
joins, where, params = self.q.get_sql(opts)
|
||||
where2 = ['(NOT (%s))' % " AND ".join(where)]
|
||||
except EmptyResultSet:
|
||||
return SortedDict(), [], []
|
||||
return joins, where2, params
|
||||
|
||||
def get_where_clause(lookup_type, table_prefix, field_name, value):
|
||||
|
@ -645,11 +694,7 @@ def get_where_clause(lookup_type, table_prefix, field_name, value):
|
|||
if in_string:
|
||||
return '%s%s IN (%s)' % (table_prefix, field_name, in_string)
|
||||
else:
|
||||
# Most backends do not accept an empty string inside the IN
|
||||
# expression, i.e. cannot do "WHERE ... IN ()". Since there are
|
||||
# also some backends that do not accept "WHERE false", we instead
|
||||
# use an expression that always evaluates to False.
|
||||
return '0=1'
|
||||
raise EmptyResultSet
|
||||
elif lookup_type == 'range':
|
||||
return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name)
|
||||
elif lookup_type in ('year', 'month', 'day'):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue