Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Jacob Kaplan-Moss authored October 24, 2009
9  django/db/models/base.py
@@ -3,11 +3,6 @@
3 3
 import sys
4 4
 import os
5 5
 from itertools import izip
6  
-try:
7  
-    set
8  
-except NameError:
9  
-    from sets import Set as set     # Python 2.3 fallback.
10  
-
11 6
 import django.db.models.manager     # Imported to register signal handler.
12 7
 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
13 8
 from django.db.models.fields import AutoField, FieldDoesNotExist
@@ -22,7 +17,6 @@
22 17
 from django.utils.encoding import smart_str, force_unicode, smart_unicode
23 18
 from django.conf import settings
24 19
 
25  
-
26 20
 class ModelBase(type):
27 21
     """
28 22
     Metaclass for all models.
@@ -236,7 +230,6 @@ def _prepare(cls):
236 230
 
237 231
         signals.class_prepared.send(sender=cls)
238 232
 
239  
-
240 233
 class Model(object):
241 234
     __metaclass__ = ModelBase
242 235
     _deferred = False
@@ -467,7 +460,7 @@ def save_base(self, raw=False, cls=None, origin=None,
467 460
             if pk_set:
468 461
                 # Determine whether a record with the primary key already exists.
469 462
                 if (force_update or (not force_insert and
470  
-                        manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
  463
+                        manager.filter(pk=pk_val).exists())):
471 464
                     # It does already exist, so do an UPDATE.
472 465
                     if force_update or non_pks:
473 466
                         values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
4  django/db/models/manager.py
... ...
@@ -1,5 +1,4 @@
1 1
 import copy
2  
-
3 2
 from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
4 3
 from django.db.models import signals
5 4
 from django.db.models.fields import FieldDoesNotExist
@@ -173,6 +172,9 @@ def defer(self, *args, **kwargs):
173 172
     def only(self, *args, **kwargs):
174 173
         return self.get_query_set().only(*args, **kwargs)
175 174
 
  175
+    def exists(self, *args, **kwargs):
  176
+        return self.get_query_ste().exists(*args, **kwargs)
  177
+
176 178
     def _insert(self, values, **kwargs):
177 179
         return insert_query(self.model, values, **kwargs)
178 180
 
12  django/db/models/query.py
@@ -2,20 +2,13 @@
2 2
 The main QuerySet implementation. This provides the public API for the ORM.
3 3
 """
4 4
 
5  
-try:
6  
-    set
7  
-except NameError:
8  
-    from sets import Set as set     # Python 2.3 fallback
9  
-
10 5
 from copy import deepcopy
11  
-
12 6
 from django.db import connection, transaction, IntegrityError
13 7
 from django.db.models.aggregates import Aggregate
14 8
 from django.db.models.fields import DateField
15 9
 from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory
16 10
 from django.db.models import signals, sql
17 11
 
18  
-
19 12
 # Used to control how many objects are worked with at once in some cases (e.g.
20 13
 # when deleting objects).
21 14
 CHUNK_SIZE = 100
@@ -444,6 +437,11 @@ def _update(self, values):
444 437
         return query.execute_sql(None)
445 438
     _update.alters_data = True
446 439
 
  440
+    def exists(self):
  441
+        if self._result_cache is None:
  442
+            return self.query.has_results()
  443
+        return bool(self._result_cache)
  444
+
447 445
     ##################################################
448 446
     # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
449 447
     ##################################################
15  django/db/models/sql/query.py
@@ -8,7 +8,6 @@
8 8
 """
9 9
 
10 10
 from copy import deepcopy
11  
-
12 11
 from django.utils.tree import Node
13 12
 from django.utils.datastructures import SortedDict
14 13
 from django.utils.encoding import force_unicode
@@ -24,11 +23,6 @@
24 23
 from datastructures import EmptyResultSet, Empty, MultiJoin
25 24
 from constants import *
26 25
 
27  
-try:
28  
-    set
29  
-except NameError:
30  
-    from sets import Set as set     # Python 2.3 fallback
31  
-
32 26
 __all__ = ['Query', 'BaseQuery']
33 27
 
34 28
 class BaseQuery(object):
@@ -384,6 +378,15 @@ def get_count(self):
384 378
 
385 379
         return number
386 380
 
  381
+    def has_results(self):
  382
+        q = self.clone()
  383
+        q.add_extra({'a': 1}, None, None, None, None, None)
  384
+        q.add_fields(())
  385
+        q.set_extra_mask(('a',))
  386
+        q.set_aggregate_mask(())
  387
+        q.clear_ordering()
  388
+        return bool(q.execute_sql())
  389
+
387 390
     def as_sql(self, with_limits=True, with_col_aliases=False):
388 391
         """
389 392
         Creates the SQL for this query. Returns the SQL string and list of
8  django/forms/models.py
@@ -319,9 +319,7 @@ def _perform_unique_checks(self, unique_checks):
319 319
             if self.instance.pk is not None:
320 320
                 qs = qs.exclude(pk=self.instance.pk)
321 321
 
322  
-            # This cute trick with extra/values is the most efficient way to
323  
-            # tell if a particular query returns any results.
324  
-            if qs.extra(select={'a': 1}).values('a').order_by():
  322
+            if qs.exists():
325 323
                 if len(unique_check) == 1:
326 324
                     self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
327 325
                 else:
@@ -354,9 +352,7 @@ def _perform_date_checks(self, date_checks):
354 352
             if self.instance.pk is not None:
355 353
                 qs = qs.exclude(pk=self.instance.pk)
356 354
 
357  
-            # This cute trick with extra/values is the most efficient way to
358  
-            # tell if a particular query returns any results.
359  
-            if qs.extra(select={'a': 1}).values('a').order_by():
  355
+            if qs.exists():
360 356
                 self._errors[field] = ErrorList([
361 357
                     self.date_error_message(lookup_type, field, unique_for)
362 358
                 ])
11  docs/ref/models/querysets.txt
@@ -1114,6 +1114,17 @@ Aggregation <topics-db-aggregation>`.
1114 1114
 
1115 1115
 .. _field-lookups:
1116 1116
 
  1117
+``exists()``
  1118
+~~~~~~~~~~~~
  1119
+
  1120
+.. versionadded:: 1.2
  1121
+
  1122
+Returns ``True`` if the :class:`QuerySet` contains any results, and ``False``
  1123
+if not. This tries to perform the query in the simplest and fastest way
  1124
+possible, but it *does* execute nearly the same query. This means that calling
  1125
+:meth:`QuerySet.exists()` is faster that ``bool(some_query_set)``, but not by
  1126
+a large degree.
  1127
+
1117 1128
 Field lookups
1118 1129
 -------------
1119 1130
 

0 notes on commit b79702b

Please sign in to comment.
Something went wrong with that request. Please try again.