From bbeeb45161da251bb7297b60d6155e7b4efdbc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E7=A9=86=E7=A9=86?= Date: Mon, 26 Dec 2022 14:13:44 +0800 Subject: [PATCH] Fixed #34226 -- Fixed QuerySet.select_related() with multiple FilteredRelations to the OneToOneField. --- django/db/models/sql/compiler.py | 4 ++-- tests/known_related_objects/models.py | 3 +++ tests/known_related_objects/tests.py | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 5423f20f1f..b9722268ed 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1265,7 +1265,7 @@ class SQLCompiler: ) get_related_klass_infos(klass_info, next_klass_infos) - def local_setter(obj, from_obj): + def local_setter(final_field, obj, from_obj): # Set a reverse fk object when relation is non-empty. if from_obj: final_field.remote_field.set_cached_value(from_obj, obj) @@ -1291,7 +1291,7 @@ class SQLCompiler: "model": model, "field": final_field, "reverse": True, - "local_setter": local_setter, + "local_setter": partial(local_setter, final_field), "remote_setter": partial(remote_setter, name), "from_parent": from_parent, } diff --git a/tests/known_related_objects/models.py b/tests/known_related_objects/models.py index bd8fd1d502..027d162828 100644 --- a/tests/known_related_objects/models.py +++ b/tests/known_related_objects/models.py @@ -24,3 +24,6 @@ class Pool(models.Model): class PoolStyle(models.Model): name = models.CharField(max_length=30) pool = models.OneToOneField(Pool, models.CASCADE) + another_pool = models.OneToOneField( + Pool, models.CASCADE, null=True, related_name="another_style" + ) diff --git a/tests/known_related_objects/tests.py b/tests/known_related_objects/tests.py index 0270220061..6080da3838 100644 --- a/tests/known_related_objects/tests.py +++ b/tests/known_related_objects/tests.py @@ -1,3 +1,4 @@ +from django.db.models import FilteredRelation from django.test import TestCase from .models import Organiser, Pool, PoolStyle, Tournament @@ -23,6 +24,9 @@ class ExistingRelatedInstancesTests(TestCase): ) cls.ps1 = PoolStyle.objects.create(name="T1 Pool 2 Style", pool=cls.p2) cls.ps2 = PoolStyle.objects.create(name="T2 Pool 1 Style", pool=cls.p3) + cls.ps3 = PoolStyle.objects.create( + name="T1 Pool 1/3 Style", pool=cls.p1, another_pool=cls.p3 + ) def test_foreign_key(self): with self.assertNumQueries(2): @@ -147,3 +151,16 @@ class ExistingRelatedInstancesTests(TestCase): pools = list(Pool.objects.prefetch_related("poolstyle").order_by("pk")) self.assertIs(pools[1], pools[1].poolstyle.pool) self.assertIs(pools[2], pools[2].poolstyle.pool) + + def test_reverse_fk_select_related_multiple(self): + with self.assertNumQueries(1): + ps = list( + PoolStyle.objects.annotate( + pool_1=FilteredRelation("pool"), + pool_2=FilteredRelation("another_pool"), + ) + .select_related("pool_1", "pool_2") + .order_by("-pk") + ) + self.assertIs(ps[0], ps[0].pool_1.poolstyle) + self.assertIs(ps[0], ps[0].pool_2.another_style)