Fixed #11402: added a `QuerySet.exists()` method. Thanks, Alex Gaynor.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11646 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
9f70783b14
commit
b79702b2de
|
@ -3,11 +3,6 @@ import types
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from itertools import izip
|
from itertools import izip
|
||||||
try:
|
|
||||||
set
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set # Python 2.3 fallback.
|
|
||||||
|
|
||||||
import django.db.models.manager # Imported to register signal handler.
|
import django.db.models.manager # Imported to register signal handler.
|
||||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
|
||||||
from django.db.models.fields import AutoField, FieldDoesNotExist
|
from django.db.models.fields import AutoField, FieldDoesNotExist
|
||||||
|
@ -22,7 +17,6 @@ from django.utils.functional import curry
|
||||||
from django.utils.encoding import smart_str, force_unicode, smart_unicode
|
from django.utils.encoding import smart_str, force_unicode, smart_unicode
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class ModelBase(type):
|
class ModelBase(type):
|
||||||
"""
|
"""
|
||||||
Metaclass for all models.
|
Metaclass for all models.
|
||||||
|
@ -236,7 +230,6 @@ class ModelBase(type):
|
||||||
|
|
||||||
signals.class_prepared.send(sender=cls)
|
signals.class_prepared.send(sender=cls)
|
||||||
|
|
||||||
|
|
||||||
class Model(object):
|
class Model(object):
|
||||||
__metaclass__ = ModelBase
|
__metaclass__ = ModelBase
|
||||||
_deferred = False
|
_deferred = False
|
||||||
|
@ -467,7 +460,7 @@ class Model(object):
|
||||||
if pk_set:
|
if pk_set:
|
||||||
# Determine whether a record with the primary key already exists.
|
# Determine whether a record with the primary key already exists.
|
||||||
if (force_update or (not force_insert and
|
if (force_update or (not force_insert and
|
||||||
manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
|
manager.filter(pk=pk_val).exists())):
|
||||||
# It does already exist, so do an UPDATE.
|
# It does already exist, so do an UPDATE.
|
||||||
if force_update or non_pks:
|
if force_update or non_pks:
|
||||||
values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
|
from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
from django.db.models.fields import FieldDoesNotExist
|
||||||
|
@ -173,6 +172,9 @@ class Manager(object):
|
||||||
def only(self, *args, **kwargs):
|
def only(self, *args, **kwargs):
|
||||||
return self.get_query_set().only(*args, **kwargs)
|
return self.get_query_set().only(*args, **kwargs)
|
||||||
|
|
||||||
|
def exists(self, *args, **kwargs):
|
||||||
|
return self.get_query_ste().exists(*args, **kwargs)
|
||||||
|
|
||||||
def _insert(self, values, **kwargs):
|
def _insert(self, values, **kwargs):
|
||||||
return insert_query(self.model, values, **kwargs)
|
return insert_query(self.model, values, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,13 @@
|
||||||
The main QuerySet implementation. This provides the public API for the ORM.
|
The main QuerySet implementation. This provides the public API for the ORM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
|
||||||
set
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set # Python 2.3 fallback
|
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from django.db import connection, transaction, IntegrityError
|
from django.db import connection, transaction, IntegrityError
|
||||||
from django.db.models.aggregates import Aggregate
|
from django.db.models.aggregates import Aggregate
|
||||||
from django.db.models.fields import DateField
|
from django.db.models.fields import DateField
|
||||||
from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory
|
from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory
|
||||||
from django.db.models import signals, sql
|
from django.db.models import signals, sql
|
||||||
|
|
||||||
|
|
||||||
# Used to control how many objects are worked with at once in some cases (e.g.
|
# Used to control how many objects are worked with at once in some cases (e.g.
|
||||||
# when deleting objects).
|
# when deleting objects).
|
||||||
CHUNK_SIZE = 100
|
CHUNK_SIZE = 100
|
||||||
|
@ -444,6 +437,11 @@ class QuerySet(object):
|
||||||
return query.execute_sql(None)
|
return query.execute_sql(None)
|
||||||
_update.alters_data = True
|
_update.alters_data = True
|
||||||
|
|
||||||
|
def exists(self):
|
||||||
|
if self._result_cache is None:
|
||||||
|
return self.query.has_results()
|
||||||
|
return bool(self._result_cache)
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
|
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
|
||||||
##################################################
|
##################################################
|
||||||
|
|
|
@ -8,7 +8,6 @@ all about the internals of models in order to get the information it needs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from django.utils.tree import Node
|
from django.utils.tree import Node
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
@ -24,11 +23,6 @@ from django.core.exceptions import FieldError
|
||||||
from datastructures import EmptyResultSet, Empty, MultiJoin
|
from datastructures import EmptyResultSet, Empty, MultiJoin
|
||||||
from constants import *
|
from constants import *
|
||||||
|
|
||||||
try:
|
|
||||||
set
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set # Python 2.3 fallback
|
|
||||||
|
|
||||||
__all__ = ['Query', 'BaseQuery']
|
__all__ = ['Query', 'BaseQuery']
|
||||||
|
|
||||||
class BaseQuery(object):
|
class BaseQuery(object):
|
||||||
|
@ -384,6 +378,15 @@ class BaseQuery(object):
|
||||||
|
|
||||||
return number
|
return number
|
||||||
|
|
||||||
|
def has_results(self):
|
||||||
|
q = self.clone()
|
||||||
|
q.add_extra({'a': 1}, None, None, None, None, None)
|
||||||
|
q.add_fields(())
|
||||||
|
q.set_extra_mask(('a',))
|
||||||
|
q.set_aggregate_mask(())
|
||||||
|
q.clear_ordering()
|
||||||
|
return bool(q.execute_sql())
|
||||||
|
|
||||||
def as_sql(self, with_limits=True, with_col_aliases=False):
|
def as_sql(self, with_limits=True, with_col_aliases=False):
|
||||||
"""
|
"""
|
||||||
Creates the SQL for this query. Returns the SQL string and list of
|
Creates the SQL for this query. Returns the SQL string and list of
|
||||||
|
|
|
@ -319,9 +319,7 @@ class BaseModelForm(BaseForm):
|
||||||
if self.instance.pk is not None:
|
if self.instance.pk is not None:
|
||||||
qs = qs.exclude(pk=self.instance.pk)
|
qs = qs.exclude(pk=self.instance.pk)
|
||||||
|
|
||||||
# This cute trick with extra/values is the most efficient way to
|
if qs.exists():
|
||||||
# tell if a particular query returns any results.
|
|
||||||
if qs.extra(select={'a': 1}).values('a').order_by():
|
|
||||||
if len(unique_check) == 1:
|
if len(unique_check) == 1:
|
||||||
self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
|
self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
|
||||||
else:
|
else:
|
||||||
|
@ -354,9 +352,7 @@ class BaseModelForm(BaseForm):
|
||||||
if self.instance.pk is not None:
|
if self.instance.pk is not None:
|
||||||
qs = qs.exclude(pk=self.instance.pk)
|
qs = qs.exclude(pk=self.instance.pk)
|
||||||
|
|
||||||
# This cute trick with extra/values is the most efficient way to
|
if qs.exists():
|
||||||
# tell if a particular query returns any results.
|
|
||||||
if qs.extra(select={'a': 1}).values('a').order_by():
|
|
||||||
self._errors[field] = ErrorList([
|
self._errors[field] = ErrorList([
|
||||||
self.date_error_message(lookup_type, field, unique_for)
|
self.date_error_message(lookup_type, field, unique_for)
|
||||||
])
|
])
|
||||||
|
|
|
@ -1114,6 +1114,17 @@ Aggregation <topics-db-aggregation>`.
|
||||||
|
|
||||||
.. _field-lookups:
|
.. _field-lookups:
|
||||||
|
|
||||||
|
``exists()``
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
Returns ``True`` if the :class:`QuerySet` contains any results, and ``False``
|
||||||
|
if not. This tries to perform the query in the simplest and fastest way
|
||||||
|
possible, but it *does* execute nearly the same query. This means that calling
|
||||||
|
:meth:`QuerySet.exists()` is faster that ``bool(some_query_set)``, but not by
|
||||||
|
a large degree.
|
||||||
|
|
||||||
Field lookups
|
Field lookups
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue