mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		| @@ -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 | ||||||
| ------------- | ------------- | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user