Code

Ticket #11402: exists.3.diff

File exists.3.diff, 4.5 KB (added by Alex, 4 years ago)

A version without unrelated admin chnages.

Line 
1diff --git a/django/db/models/base.py b/django/db/models/base.py
2index a5c9986..30b12da 100644
3--- a/django/db/models/base.py
4+++ b/django/db/models/base.py
5@@ -467,7 +467,7 @@ class Model(object):
6             if pk_set:
7                 # Determine whether a record with the primary key already exists.
8                 if (force_update or (not force_insert and
9-                        manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
10+                        manager.filter(pk=pk_val).exists())):
11                     # It does already exist, so do an UPDATE.
12                     if force_update or non_pks:
13                         values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
14diff --git a/django/db/models/manager.py b/django/db/models/manager.py
15index 52612d8..73d2bf5 100644
16--- a/django/db/models/manager.py
17+++ b/django/db/models/manager.py
18@@ -172,6 +172,9 @@ class Manager(object):
19 
20     def only(self, *args, **kwargs):
21         return self.get_query_set().only(*args, **kwargs)
22+   
23+    def exists(self, *args, **kwargs):
24+        return self.get_query_ste().exists(*args, **kwargs)
25 
26     def _insert(self, values, **kwargs):
27         return insert_query(self.model, values, **kwargs)
28diff --git a/django/db/models/query.py b/django/db/models/query.py
29index 46a86fc..02288c1 100644
30--- a/django/db/models/query.py
31+++ b/django/db/models/query.py
32@@ -443,6 +443,11 @@ class QuerySet(object):
33         self._result_cache = None
34         return query.execute_sql(None)
35     _update.alters_data = True
36+   
37+    def exists(self):
38+        if self._result_cache is None:
39+            return self.query.has_results()
40+        return bool(self._result_cache)
41 
42     ##################################################
43     # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
44diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
45index 23f99e4..ad0998b 100644
46--- a/django/db/models/sql/query.py
47+++ b/django/db/models/sql/query.py
48@@ -383,6 +383,23 @@ class BaseQuery(object):
49             number = min(number, self.high_mark - self.low_mark)
50 
51         return number
52+   
53+    def has_results(self):
54+        """
55+        Returns whether or not there are any items in the result set this Query
56+        represents.  Does this in a super tricking way.  Basically the
57+        equivalent of QuerySet.extra(select={'a': 1}).values('a').order_by()
58+        to maximize efficiency.
59+        """
60+        c = self.clone()
61+        c.add_extra({'a': 1}, None, None, None, None, None)
62+        c.add_fields(())
63+        c.set_extra_mask(('a',))
64+        c.set_aggregate_mask(())
65+        c.clear_ordering()
66+        results = self.execute_sql()
67+        return bool(results)
68+
69 
70     def as_sql(self, with_limits=True, with_col_aliases=False):
71         """
72diff --git a/django/forms/models.py b/django/forms/models.py
73index cc43612..37fce68 100644
74--- a/django/forms/models.py
75+++ b/django/forms/models.py
76@@ -319,9 +319,7 @@ class BaseModelForm(BaseForm):
77             if self.instance.pk is not None:
78                 qs = qs.exclude(pk=self.instance.pk)
79 
80-            # This cute trick with extra/values is the most efficient way to
81-            # tell if a particular query returns any results.
82-            if qs.extra(select={'a': 1}).values('a').order_by():
83+            if qs.exists():
84                 if len(unique_check) == 1:
85                     self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
86                 else:
87@@ -354,9 +352,7 @@ class BaseModelForm(BaseForm):
88             if self.instance.pk is not None:
89                 qs = qs.exclude(pk=self.instance.pk)
90 
91-            # This cute trick with extra/values is the most efficient way to
92-            # tell if a particular query returns any results.
93-            if qs.extra(select={'a': 1}).values('a').order_by():
94+            if qs.exists():
95                 self._errors[field] = ErrorList([
96                     self.date_error_message(lookup_type, field, unique_for)
97                 ])
98diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
99index efd7c54..26c76ca 100644
100--- a/docs/ref/models/querysets.txt
101+++ b/docs/ref/models/querysets.txt
102@@ -1114,6 +1114,12 @@ Aggregation <topics-db-aggregation>`.
103 
104 .. _field-lookups:
105 
106+``exists()``
107+~~~~~~~~~~~~
108+
109+Returns whether or not there are any items in the ``QuerySet``.  This will
110+perform the query in the most efficient way possible.
111+
112 Field lookups
113 -------------
114