Fixed #34570 -- Silenced noop deferral of many-to-many and GFK.

While deferring many-to-many and GFK has no effect, the previous
implementation of QuerySet.defer() ignore them instead of crashing.

Regression in b3db6c8dcb.

Thanks Paco Martínez for the report.
This commit is contained in:
Simon Charette 2023-05-16 15:11:19 -04:00 committed by Mariusz Felisiak
parent 0ec60661e6
commit 99e5dff737
3 changed files with 19 additions and 1 deletions

View File

@ -738,7 +738,15 @@ class Query(BaseExpression):
field_select_mask = select_mask.setdefault((field_name, relation), {})
field = relation.field
else:
field = opts.get_field(field_name).field
reverse_rel = opts.get_field(field_name)
# While virtual fields such as many-to-many and generic foreign
# keys cannot be effectively deferred we've historically
# allowed them to be passed to QuerySet.defer(). Ignore such
# field references until a layer of validation at mask
# alteration time will be implemented eventually.
if not hasattr(reverse_rel, "field"):
continue
field = reverse_rel.field
field_select_mask = select_mask.setdefault(field, {})
related_model = field.model._meta.concrete_model
self._get_defer_select_mask(

View File

@ -15,3 +15,7 @@ Bugfixes
* Restored, following a regression in Django 4.2, ``get_prep_value()`` call in
``JSONField`` subclasses (:ticket:`34539`).
* Fixed a regression in Django 4.2 that caused a crash of ``QuerySet.defer()``
when passing a ``ManyToManyField`` or ``GenericForeignKey`` reference. While
doing so is a no-op, it was allowed in older version (:ticket:`34570`).

View File

@ -271,6 +271,12 @@ class DeferRegressionTest(TestCase):
with self.assertNumQueries(1):
self.assertEqual(leaf.second_child.value, 64)
def test_defer_many_to_many_ignored(self):
location = Location.objects.create()
request = Request.objects.create(location=location)
with self.assertNumQueries(1):
self.assertEqual(Request.objects.defer("items").get(), request)
class DeferDeletionSignalsTests(TestCase):
senders = [Item, Proxy]