summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2023-05-16 15:11:19 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-05-17 08:39:44 +0200
commit201d29b3719ef15637648be7bd947ef90a66ab55 (patch)
tree57f798e90dcbfd8b0cdfc588a3d0c52837be33d5
parent9c301814b0d342bfc5f10c1513594ce5fbb6c6a9 (diff)
[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 b3db6c8dcb5145f7d45eff517bcd96460475c879. Thanks Paco Martínez for the report. Backport of 99e5dff737cd20b12d060e4794e097063b61ec40 from main
-rw-r--r--django/db/models/sql/query.py10
-rw-r--r--docs/releases/4.2.2.txt4
-rw-r--r--tests/defer_regress/tests.py6
3 files changed, 19 insertions, 1 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index b347c6bf3f..b615d06f28 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -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(
diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt
index a92582b7a0..ca21e5f1ec 100644
--- a/docs/releases/4.2.2.txt
+++ b/docs/releases/4.2.2.txt
@@ -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`).
diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py
index 9f94d5fac1..ab2be085c6 100644
--- a/tests/defer_regress/tests.py
+++ b/tests/defer_regress/tests.py
@@ -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]