Code

Ticket #11402: exists.diff

File exists.diff, 4.2 KB (added by Alex, 4 years ago)
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..4d4a332 100644
30--- a/django/db/models/query.py
31+++ b/django/db/models/query.py
32@@ -443,6 +443,12 @@ 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+            c = self.query.clone()
40+            return c.has_results()
41+        return bool(self._result_cache)
42 
43     ##################################################
44     # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
45diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
46index 23f99e4..663aa1e 100644
47--- a/django/db/models/sql/query.py
48+++ b/django/db/models/sql/query.py
49@@ -383,6 +383,16 @@ class BaseQuery(object):
50             number = min(number, self.high_mark - self.low_mark)
51 
52         return number
53+   
54+    def has_results(self):
55+        self.add_extra({'a': 1}, None, None, None, None, None)
56+        self.add_fields(())
57+        self.set_extra_mask(('a',))
58+        self.set_aggregate_mask(())
59+        self.clear_ordering()
60+        results = self.execute_sql()
61+        return bool(results)
62+
63 
64     def as_sql(self, with_limits=True, with_col_aliases=False):
65         """
66diff --git a/django/forms/models.py b/django/forms/models.py
67index cc43612..37fce68 100644
68--- a/django/forms/models.py
69+++ b/django/forms/models.py
70@@ -319,9 +319,7 @@ class BaseModelForm(BaseForm):
71             if self.instance.pk is not None:
72                 qs = qs.exclude(pk=self.instance.pk)
73 
74-            # This cute trick with extra/values is the most efficient way to
75-            # tell if a particular query returns any results.
76-            if qs.extra(select={'a': 1}).values('a').order_by():
77+            if qs.exists():
78                 if len(unique_check) == 1:
79                     self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
80                 else:
81@@ -354,9 +352,7 @@ class BaseModelForm(BaseForm):
82             if self.instance.pk is not None:
83                 qs = qs.exclude(pk=self.instance.pk)
84 
85-            # This cute trick with extra/values is the most efficient way to
86-            # tell if a particular query returns any results.
87-            if qs.extra(select={'a': 1}).values('a').order_by():
88+            if qs.exists():
89                 self._errors[field] = ErrorList([
90                     self.date_error_message(lookup_type, field, unique_for)
91                 ])
92diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
93index efd7c54..66f0ba9 100644
94--- a/docs/ref/models/querysets.txt
95+++ b/docs/ref/models/querysets.txt
96@@ -1114,6 +1114,12 @@ Aggregation <topics-db-aggregation>`.
97 
98 .. _field-lookups:
99 
100+``exists()``
101+~~~~~~~~~~~~
102+
103+Returns whether or not there are any items in the ``QuerySet``.  This will
104+perform the query in the simplest way possible.
105+
106 Field lookups
107 -------------
108