1
0
mirror of https://github.com/django/django.git synced 2025-01-13 11:57:01 +00:00

[4.2.x] 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.

Backport of 99e5dff737 from main
This commit is contained in:
Simon Charette 2023-05-16 15:11:19 -04:00 committed by Mariusz Felisiak
parent 9c301814b0
commit 201d29b371
3 changed files with 19 additions and 1 deletions

View File

@ -725,7 +725,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

@ -296,6 +296,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]