Commit 4c3bfe90 authored by Loic Bistuer's avatar Loic Bistuer
Browse files

Fixed #24211 -- Removed ValuesQuerySet() and ValuesListQuerySet().

Thanks Anssi Kääriäinen, Marc Tamlyn, and Tim Graham for the reviews.
parent dbabf439
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -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()
@@ -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))
+229 −310

File changed.

Preview size limit exceeded, changes collapsed.

+9 −4
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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
@@ -1616,6 +1620,7 @@ class Query(object):
        columns.
        """
        self.select = []
        self.values_select = []

    def add_select(self, col):
        self.default_cols = False
+1 −1
Original line number Diff line number Diff line
@@ -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()
+11 −18
Original line number Diff line number Diff line
@@ -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.
@@ -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()
@@ -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
~~~~~

@@ -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