Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit b79702b2deec4ca3c625e5bffe46fa976c3c4e5f 1 parent 9f70783
@jacobian jacobian authored
View
9 django/db/models/base.py
@@ -3,11 +3,6 @@
import sys
import os
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.
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
from django.db.models.fields import AutoField, FieldDoesNotExist
@@ -22,7 +17,6 @@
from django.utils.encoding import smart_str, force_unicode, smart_unicode
from django.conf import settings
-
class ModelBase(type):
"""
Metaclass for all models.
@@ -236,7 +230,6 @@ def _prepare(cls):
signals.class_prepared.send(sender=cls)
-
class Model(object):
__metaclass__ = ModelBase
_deferred = False
@@ -467,7 +460,7 @@ def save_base(self, raw=False, cls=None, origin=None,
if pk_set:
# Determine whether a record with the primary key already exists.
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.
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]
View
4 django/db/models/manager.py
@@ -1,5 +1,4 @@
import copy
-
from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
from django.db.models import signals
from django.db.models.fields import FieldDoesNotExist
@@ -173,6 +172,9 @@ def defer(self, *args, **kwargs):
def only(self, *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):
return insert_query(self.model, values, **kwargs)
View
12 django/db/models/query.py
@@ -2,20 +2,13 @@
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 django.db import connection, transaction, IntegrityError
from django.db.models.aggregates import Aggregate
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 import signals, sql
-
# Used to control how many objects are worked with at once in some cases (e.g.
# when deleting objects).
CHUNK_SIZE = 100
@@ -444,6 +437,11 @@ def _update(self, values):
return query.execute_sql(None)
_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 #
##################################################
View
15 django/db/models/sql/query.py
@@ -8,7 +8,6 @@
"""
from copy import deepcopy
-
from django.utils.tree import Node
from django.utils.datastructures import SortedDict
from django.utils.encoding import force_unicode
@@ -24,11 +23,6 @@
from datastructures import EmptyResultSet, Empty, MultiJoin
from constants import *
-try:
- set
-except NameError:
- from sets import Set as set # Python 2.3 fallback
-
__all__ = ['Query', 'BaseQuery']
class BaseQuery(object):
@@ -384,6 +378,15 @@ def get_count(self):
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):
"""
Creates the SQL for this query. Returns the SQL string and list of
View
8 django/forms/models.py
@@ -319,9 +319,7 @@ def _perform_unique_checks(self, unique_checks):
if self.instance.pk is not None:
qs = qs.exclude(pk=self.instance.pk)
- # This cute trick with extra/values is the most efficient way to
- # tell if a particular query returns any results.
- if qs.extra(select={'a': 1}).values('a').order_by():
+ if qs.exists():
if len(unique_check) == 1:
self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
else:
@@ -354,9 +352,7 @@ def _perform_date_checks(self, date_checks):
if self.instance.pk is not None:
qs = qs.exclude(pk=self.instance.pk)
- # This cute trick with extra/values is the most efficient way to
- # tell if a particular query returns any results.
- if qs.extra(select={'a': 1}).values('a').order_by():
+ if qs.exists():
self._errors[field] = ErrorList([
self.date_error_message(lookup_type, field, unique_for)
])
View
11 docs/ref/models/querysets.txt
@@ -1114,6 +1114,17 @@ Aggregation <topics-db-aggregation>`.
.. _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
-------------
Please sign in to comment.
Something went wrong with that request. Please try again.