Fixed #22023 -- Raised an error for values() followed by defer() or only().
Previously, doing so resulted in invalid data or crash. Thanks jtiai for the report and Karol Jochelson, Jakub Nowak, Loic Bistuer, and Baptiste Mispelon for reviews.
This commit is contained in:
parent
a7639722f5
commit
faf6a911ad
|
@ -1060,6 +1060,12 @@ class ValuesQuerySet(QuerySet):
|
||||||
# QuerySet.clone() will also set up the _fields attribute with the
|
# QuerySet.clone() will also set up the _fields attribute with the
|
||||||
# names of the model fields to select.
|
# names of the model fields to select.
|
||||||
|
|
||||||
|
def only(self, *fields):
|
||||||
|
raise NotImplementedError("ValuesQuerySet does not implement only()")
|
||||||
|
|
||||||
|
def defer(self, *fields):
|
||||||
|
raise NotImplementedError("ValuesQuerySet does not implement defer()")
|
||||||
|
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
# Purge any extra columns that haven't been explicitly asked for
|
# Purge any extra columns that haven't been explicitly asked for
|
||||||
extra_names = list(self.query.extra_select)
|
extra_names = list(self.query.extra_select)
|
||||||
|
|
|
@ -502,14 +502,23 @@ A few subtleties that are worth mentioning:
|
||||||
made after a ``values()`` call will have its extra selected fields
|
made after a ``values()`` call will have its extra selected fields
|
||||||
ignored.
|
ignored.
|
||||||
|
|
||||||
|
* Calling :meth:`only()` and :meth:`defer()` after ``values()`` doesn't make
|
||||||
|
sense, so doing so will raise a ``NotImplementedError``.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
|
||||||
|
The last point above is new. Previously, calling :meth:`only()` and
|
||||||
|
: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
|
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
|
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
|
functionality of a model instance object. It's more efficient to select only
|
||||||
the fields you need to use.
|
the fields you need to use.
|
||||||
|
|
||||||
Finally, note a ``ValuesQuerySet`` is a subclass of ``QuerySet``, so it has all
|
Finally, note that a ``ValuesQuerySet`` is a subclass of ``QuerySet`` and it
|
||||||
methods of ``QuerySet``. You can call ``filter()`` on it, or ``order_by()``, or
|
implements most of the same methods. You can call ``filter()`` on it,
|
||||||
whatever. Yes, that means these two calls are identical::
|
``order_by()``, etc. That means that these two calls are identical::
|
||||||
|
|
||||||
Blog.objects.values().order_by('id')
|
Blog.objects.values().order_by('id')
|
||||||
Blog.objects.order_by('id').values()
|
Blog.objects.order_by('id').values()
|
||||||
|
|
|
@ -616,6 +616,12 @@ Models
|
||||||
:attr:`~django.db.models.ForeignKey.limit_choices_to` when defining a
|
:attr:`~django.db.models.ForeignKey.limit_choices_to` when defining a
|
||||||
``ForeignKey`` or ``ManyToManyField``.
|
``ForeignKey`` or ``ManyToManyField``.
|
||||||
|
|
||||||
|
* Calling :meth:`only() <django.db.models.query.QuerySet.only>` and
|
||||||
|
:meth:`defer() <django.db.models.query.QuerySet.defer>` on the result of
|
||||||
|
:meth:`QuerySet.values() <django.db.models.query.QuerySet.values>` now raises
|
||||||
|
an error (before that, it would either result in a database error or
|
||||||
|
incorrect data).
|
||||||
|
|
||||||
Signals
|
Signals
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -1275,6 +1275,16 @@ class Queries3Tests(BaseQuerysetTest):
|
||||||
Item.objects.datetimes, 'name', 'month'
|
Item.objects.datetimes, 'name', 'month'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_ticket22023(self):
|
||||||
|
# only() and defer() are not applicable for ValuesQuerySet
|
||||||
|
with self.assertRaisesMessage(NotImplementedError,
|
||||||
|
"ValuesQuerySet does not implement only()"):
|
||||||
|
Valid.objects.values().only()
|
||||||
|
|
||||||
|
with self.assertRaisesMessage(NotImplementedError,
|
||||||
|
"ValuesQuerySet does not implement defer()"):
|
||||||
|
Valid.objects.values().defer()
|
||||||
|
|
||||||
|
|
||||||
class Queries4Tests(BaseQuerysetTest):
|
class Queries4Tests(BaseQuerysetTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue