Added QuerySet.exclude() which does the opposite of QuerySet.filter(). As a side effect, the "ne" lookup type no longer exists. This fixes #966.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2422 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jacob Kaplan-Moss 2006-02-27 22:51:36 +00:00
parent 05bc38b2b4
commit 9cdd49c1e0
7 changed files with 28 additions and 6 deletions

View File

@ -119,7 +119,6 @@ OPERATOR_MAPPING = {
'iexact': 'LIKE %s',
'contains': 'LIKE %s',
'icontains': 'LIKE %s',
'ne': '!= %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',

View File

@ -132,7 +132,6 @@ OPERATOR_MAPPING = {
'iexact': 'LIKE %s',
'contains': 'LIKE BINARY %s',
'icontains': 'LIKE %s',
'ne': '!= %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',

View File

@ -107,7 +107,6 @@ OPERATOR_MAPPING = {
'iexact': 'ILIKE %s',
'contains': 'LIKE %s',
'icontains': 'ILIKE %s',
'ne': '!= %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',

View File

@ -131,7 +131,6 @@ OPERATOR_MAPPING = {
'iexact': "LIKE %s ESCAPE '\\'",
'contains': "LIKE %s ESCAPE '\\'",
'icontains': "LIKE %s ESCAPE '\\'",
'ne': '!= %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',

View File

@ -69,6 +69,9 @@ class Manager(object):
def filter(self, *args, **kwargs):
return self.get_query_set().filter(*args, **kwargs)
def exclude(self, *args, **kwargs):
return self.get_query_set().exclude(*args, **kwargs)
def in_bulk(self, *args, **kwargs):
return self.get_query_set().in_bulk(*args, **kwargs)

View File

@ -244,9 +244,16 @@ class QuerySet(object):
def filter(self, *args, **kwargs):
"Returns a new QuerySet instance with the args ANDed to the existing set."
return self._filter_or_exclude(Q, *args, **kwargs)
def exclude(self, *args, **kwargs):
"Returns a new QuerySet instance with NOT (arsg) ANDed to the existing set."
return self._filter_or_exclude(QNot, *args, **kwargs)
def _filter_or_exclude(self, qtype, *args, **kwargs):
clone = self._clone()
if len(kwargs) > 0:
clone._filters = clone._filters & Q(**kwargs)
clone._filters = clone._filters & qtype(**kwargs)
if len(args) > 0:
clone._filters = clone._filters & reduce(operator.and_, args)
return clone
@ -490,7 +497,7 @@ class QOr(QOperator):
else:
raise TypeError, other
class Q:
class Q(object):
"Encapsulates queries as objects that can be combined logically."
def __init__(self, **kwargs):
self.kwargs = kwargs
@ -504,6 +511,14 @@ class Q:
def get_sql(self, opts):
return parse_lookup(self.kwargs.items(), opts)
class QNot(Q):
"Encapsulates NOT (...) queries as objects"
def get_sql(self, opts):
tables, joins, where, params = super(QNot, self).get_sql(opts)
where2 = ['(NOT (%s))' % " AND ".join(where)]
return tables, joins, where2, params
def get_where_clause(lookup_type, table_prefix, field_name, value):
if table_prefix.endswith('.'):
table_prefix = backend.quote_name(table_prefix[:-1])+'.'

View File

@ -170,4 +170,12 @@ Article 1
[Article% with percent sign, Article_ with underscore, Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
>>> Article.objects.filter(headline__startswith='Article%')
[Article% with percent sign]
# exclude() is the opposite of filter() when doing lookups:
>>> Article.objects.filter(headline__contains='Article').exclude(headline__contains='with')
[Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
>>> Article.objects.exclude(headline__startswith="Article_")
[Article% with percent sign, Article 5, Article 6, Article 4, Article 2, Article 3, Article 7, Article 1]
>>> Article.objects.exclude(headline="Article 7")
[Article% with percent sign, Article_ with underscore, Article 5, Article 6, Article 4, Article 2, Article 3, Article 1]cl
"""