summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author朱穆穆 <mumu.zhu@feat.com>2022-12-29 10:23:46 +0800
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-01-24 10:20:27 +0100
commitd3c93cdc597e0efc2815111c04dd5a427432ed37 (patch)
tree3b09888fcf698f51ac25fb6d0838cda890901d25
parentef85b6bf0bc5a8b194f0724cf5bbedbcee402b96 (diff)
Fixed #34227 -- Fixed QuerySet.select_related() with multi-level FilteredRelation.
-rw-r--r--django/db/models/sql/compiler.py9
-rw-r--r--tests/known_related_objects/tests.py20
2 files changed, 28 insertions, 1 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 7c433b3f06..c07076d54a 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -1274,6 +1274,9 @@ class SQLCompiler:
if from_obj:
final_field.remote_field.set_cached_value(from_obj, obj)
+ def local_setter_noop(obj, from_obj):
+ pass
+
def remote_setter(name, obj, from_obj):
setattr(from_obj, name, obj)
@@ -1295,7 +1298,11 @@ class SQLCompiler:
"model": model,
"field": final_field,
"reverse": True,
- "local_setter": partial(local_setter, final_field),
+ "local_setter": (
+ partial(local_setter, final_field)
+ if len(joins) <= 2
+ else local_setter_noop
+ ),
"remote_setter": partial(remote_setter, name),
"from_parent": from_parent,
}
diff --git a/tests/known_related_objects/tests.py b/tests/known_related_objects/tests.py
index 6080da3838..371c73d395 100644
--- a/tests/known_related_objects/tests.py
+++ b/tests/known_related_objects/tests.py
@@ -164,3 +164,23 @@ class ExistingRelatedInstancesTests(TestCase):
)
self.assertIs(ps[0], ps[0].pool_1.poolstyle)
self.assertIs(ps[0], ps[0].pool_2.another_style)
+
+ def test_multilevel_reverse_fk_cyclic_select_related(self):
+ with self.assertNumQueries(3):
+ p = list(
+ PoolStyle.objects.annotate(
+ tournament_pool=FilteredRelation("pool__tournament__pool"),
+ ).select_related("tournament_pool", "tournament_pool__tournament")
+ )
+ self.assertEqual(p[0].tournament_pool.tournament, p[0].pool.tournament)
+
+ def test_multilevel_reverse_fk_select_related(self):
+ with self.assertNumQueries(2):
+ p = list(
+ Tournament.objects.filter(id=self.t2.id)
+ .annotate(
+ style=FilteredRelation("pool__another_style"),
+ )
+ .select_related("style")
+ )
+ self.assertEqual(p[0].style.another_pool, self.p3)