Loading django/contrib/gis/tests/relatedapp/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ class RelatedGeoModelTest(TestCase): def test07_values(self): "Testing values() and values_list() and GeoQuerySets." # GeoQuerySet and GeoValuesQuerySet, and GeoValuesListQuerySet respectively. gqs = Location.objects.all() gvqs = Location.objects.values() gvlqs = Location.objects.values_list() Loading Loading @@ -264,7 +263,7 @@ class RelatedGeoModelTest(TestCase): "Testing `Count` aggregate use with the `GeoManager` on non geo-fields. See #11087." # Should only be one author (Trevor Paglen) returned by this query, and # the annotation should have 3 for the number of books, see #11087. # Also testing with a `GeoValuesQuerySet`, see #11489. # Also testing with a values(), see #11489. qs = Author.objects.annotate(num_books=Count('books')).filter(num_books__gt=1) vqs = Author.objects.values('name').annotate(num_books=Count('books')).filter(num_books__gt=1) self.assertEqual(1, len(qs)) Loading django/db/models/query.py +229 −310 File changed.Preview size limit exceeded, changes collapsed. Show changes django/db/models/sql/query.py +9 −4 Original line number Diff line number Diff line Loading @@ -148,7 +148,14 @@ class Query(object): self.distinct_fields = [] self.select_for_update = False self.select_for_update_nowait = False self.select_related = False # Arbitrary limit for select_related to prevents infinite recursion. self.max_depth = 5 # Holds the selects defined by a call to values() or values_list() # excluding annotation_select and extra_select. self.values_select = [] # SQL annotation-related attributes # The _annotations will be an OrderedDict when used. Due to the cost Loading @@ -158,10 +165,6 @@ class Query(object): self.annotation_select_mask = None self._annotation_select_cache = None # Arbitrary maximum limit for select_related. Prevents infinite # recursion. Can be changed by the depth parameter to select_related(). self.max_depth = 5 # These are for extensions. The contents are more or less appended # verbatim to the appropriate clause. # The _extra attribute is an OrderedDict, lazily created similarly to Loading Loading @@ -273,6 +276,7 @@ class Query(object): obj.select_for_update = self.select_for_update obj.select_for_update_nowait = self.select_for_update_nowait obj.select_related = self.select_related obj.values_select = self.values_select[:] obj._annotations = self._annotations.copy() if self._annotations is not None else None if self.annotation_select_mask is None: obj.annotation_select_mask = None Loading Loading @@ -1616,6 +1620,7 @@ class Query(object): columns. """ self.select = [] self.values_select = [] def add_select(self, col): self.default_cols = False Loading django/db/models/sql/where.py +1 −1 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ class SubqueryConstraint(object): if query._db and connection.alias != query._db: raise ValueError("Can't do subqueries with queries on different DBs.") # Do not override already existing values. if not hasattr(query, 'field_names'): if query._fields is None: query = query.values(*self.targets) else: query = query._clone() Loading docs/ref/models/querysets.txt +11 −18 Original line number Diff line number Diff line Loading @@ -514,8 +514,8 @@ values .. method:: values(*fields) Returns a ``ValuesQuerySet`` — a ``QuerySet`` subclass that returns dictionaries when used as an iterable, rather than model-instance objects. Returns a ``QuerySet`` that returns dictionaries, rather than model instances, when used as an iterable. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects. Loading Loading @@ -585,14 +585,12 @@ A few subtleties that are worth mentioning: :meth:`defer()` after ``values()`` was allowed, but it either crashed or returned incorrect results. A ``ValuesQuerySet`` is useful when you know you're only going to need values from a small number of the available fields and you won't need the functionality of a model instance object. It's more efficient to select only the fields you need to use. It is useful when you know you're only going to need values from a small number of the available fields and you won't need the functionality of a model instance object. It's more efficient to select only the fields you need to use. Finally, note that a ``ValuesQuerySet`` is a subclass of ``QuerySet`` and it implements most of the same methods. You can call ``filter()`` on it, ``order_by()``, etc. That means that these two calls are identical:: Finally, note that you can call ``filter()``, ``order_by()``, etc. after the ``values()`` call, that means that these two calls are identical:: Blog.objects.values().order_by('id') Blog.objects.order_by('id').values() Loading Loading @@ -645,11 +643,6 @@ It is an error to pass in ``flat`` when there is more than one field. If you don't pass any values to ``values_list()``, it will return all the fields in the model, in the order they were declared. Note that this method returns a ``ValuesListQuerySet``. This class behaves like a list. Most of the time this is enough, but if you require an actual Python list object, you can simply call ``list()`` on it, which will evaluate the queryset. dates ~~~~~ Loading Loading @@ -2280,10 +2273,10 @@ This queryset will be evaluated as subselect statement:: SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%') If you pass in a ``ValuesQuerySet`` or ``ValuesListQuerySet`` (the result of calling ``values()`` or ``values_list()`` on a queryset) as the value to an ``__in`` lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):: If you pass in a ``QuerySet`` resulting from ``values()`` or ``values_list()`` as the value to an ``__in`` lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):: inner_qs = Blog.objects.filter(name__contains='Ch').values('name') entries = Entry.objects.filter(blog__name__in=inner_qs) Loading Loading
django/contrib/gis/tests/relatedapp/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ class RelatedGeoModelTest(TestCase): def test07_values(self): "Testing values() and values_list() and GeoQuerySets." # GeoQuerySet and GeoValuesQuerySet, and GeoValuesListQuerySet respectively. gqs = Location.objects.all() gvqs = Location.objects.values() gvlqs = Location.objects.values_list() Loading Loading @@ -264,7 +263,7 @@ class RelatedGeoModelTest(TestCase): "Testing `Count` aggregate use with the `GeoManager` on non geo-fields. See #11087." # Should only be one author (Trevor Paglen) returned by this query, and # the annotation should have 3 for the number of books, see #11087. # Also testing with a `GeoValuesQuerySet`, see #11489. # Also testing with a values(), see #11489. qs = Author.objects.annotate(num_books=Count('books')).filter(num_books__gt=1) vqs = Author.objects.values('name').annotate(num_books=Count('books')).filter(num_books__gt=1) self.assertEqual(1, len(qs)) Loading
django/db/models/query.py +229 −310 File changed.Preview size limit exceeded, changes collapsed. Show changes
django/db/models/sql/query.py +9 −4 Original line number Diff line number Diff line Loading @@ -148,7 +148,14 @@ class Query(object): self.distinct_fields = [] self.select_for_update = False self.select_for_update_nowait = False self.select_related = False # Arbitrary limit for select_related to prevents infinite recursion. self.max_depth = 5 # Holds the selects defined by a call to values() or values_list() # excluding annotation_select and extra_select. self.values_select = [] # SQL annotation-related attributes # The _annotations will be an OrderedDict when used. Due to the cost Loading @@ -158,10 +165,6 @@ class Query(object): self.annotation_select_mask = None self._annotation_select_cache = None # Arbitrary maximum limit for select_related. Prevents infinite # recursion. Can be changed by the depth parameter to select_related(). self.max_depth = 5 # These are for extensions. The contents are more or less appended # verbatim to the appropriate clause. # The _extra attribute is an OrderedDict, lazily created similarly to Loading Loading @@ -273,6 +276,7 @@ class Query(object): obj.select_for_update = self.select_for_update obj.select_for_update_nowait = self.select_for_update_nowait obj.select_related = self.select_related obj.values_select = self.values_select[:] obj._annotations = self._annotations.copy() if self._annotations is not None else None if self.annotation_select_mask is None: obj.annotation_select_mask = None Loading Loading @@ -1616,6 +1620,7 @@ class Query(object): columns. """ self.select = [] self.values_select = [] def add_select(self, col): self.default_cols = False Loading
django/db/models/sql/where.py +1 −1 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ class SubqueryConstraint(object): if query._db and connection.alias != query._db: raise ValueError("Can't do subqueries with queries on different DBs.") # Do not override already existing values. if not hasattr(query, 'field_names'): if query._fields is None: query = query.values(*self.targets) else: query = query._clone() Loading
docs/ref/models/querysets.txt +11 −18 Original line number Diff line number Diff line Loading @@ -514,8 +514,8 @@ values .. method:: values(*fields) Returns a ``ValuesQuerySet`` — a ``QuerySet`` subclass that returns dictionaries when used as an iterable, rather than model-instance objects. Returns a ``QuerySet`` that returns dictionaries, rather than model instances, when used as an iterable. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects. Loading Loading @@ -585,14 +585,12 @@ A few subtleties that are worth mentioning: :meth:`defer()` after ``values()`` was allowed, but it either crashed or returned incorrect results. A ``ValuesQuerySet`` is useful when you know you're only going to need values from a small number of the available fields and you won't need the functionality of a model instance object. It's more efficient to select only the fields you need to use. It is useful when you know you're only going to need values from a small number of the available fields and you won't need the functionality of a model instance object. It's more efficient to select only the fields you need to use. Finally, note that a ``ValuesQuerySet`` is a subclass of ``QuerySet`` and it implements most of the same methods. You can call ``filter()`` on it, ``order_by()``, etc. That means that these two calls are identical:: Finally, note that you can call ``filter()``, ``order_by()``, etc. after the ``values()`` call, that means that these two calls are identical:: Blog.objects.values().order_by('id') Blog.objects.order_by('id').values() Loading Loading @@ -645,11 +643,6 @@ It is an error to pass in ``flat`` when there is more than one field. If you don't pass any values to ``values_list()``, it will return all the fields in the model, in the order they were declared. Note that this method returns a ``ValuesListQuerySet``. This class behaves like a list. Most of the time this is enough, but if you require an actual Python list object, you can simply call ``list()`` on it, which will evaluate the queryset. dates ~~~~~ Loading Loading @@ -2280,10 +2273,10 @@ This queryset will be evaluated as subselect statement:: SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%') If you pass in a ``ValuesQuerySet`` or ``ValuesListQuerySet`` (the result of calling ``values()`` or ``values_list()`` on a queryset) as the value to an ``__in`` lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):: If you pass in a ``QuerySet`` resulting from ``values()`` or ``values_list()`` as the value to an ``__in`` lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):: inner_qs = Blog.objects.filter(name__contains='Ch').values('name') entries = Entry.objects.filter(blog__name__in=inner_qs) Loading