summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/contenttypes/fields.py14
-rw-r--r--django/db/models/fields/related_descriptors.py2
-rw-r--r--tests/prefetch_related/tests.py14
3 files changed, 29 insertions, 1 deletions
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index a3e87f6ed4..4905fd1fff 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -402,6 +402,20 @@ class GenericRelation(ForeignObject):
)
]
+ def get_local_related_value(self, instance):
+ return self.get_instance_value_for_fields(instance, self.foreign_related_fields)
+
+ def get_foreign_related_value(self, instance):
+ # We (possibly) need to convert object IDs to the type of the
+ # instances' PK in order to match up instances during prefetching.
+ return tuple(
+ foreign_field.to_python(val)
+ for foreign_field, val in zip(
+ self.foreign_related_fields,
+ self.get_instance_value_for_fields(instance, self.local_related_fields),
+ )
+ )
+
def _get_path_info_with_parent(self, filtered_relation):
"""
Return the path that joins the current model through any parent models.
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index 6584e864db..d858144152 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -794,7 +794,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
for rel_obj in queryset:
if not self.field.is_cached(rel_obj):
instance = instances_dict[rel_obj_attr(rel_obj)]
- setattr(rel_obj, self.field.name, instance)
+ self.field.set_cached_value(rel_obj, instance)
cache_name = self.field.remote_field.cache_name
return queryset, rel_obj_attr, instance_attr, False, cache_name, False
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index 856f766d30..99e3cd6b80 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -1257,6 +1257,20 @@ class GenericRelationTests(TestCase):
],
)
+ def test_reverse_generic_relation(self):
+ # Create two distinct bookmarks to ensure the bookmark and
+ # tagged item models primary are offset.
+ first_bookmark = Bookmark.objects.create()
+ second_bookmark = Bookmark.objects.create()
+ TaggedItem.objects.create(
+ content_object=first_bookmark, favorite=second_bookmark
+ )
+ with self.assertNumQueries(2):
+ obj = TaggedItem.objects.prefetch_related("favorite_bookmarks").get()
+ with self.assertNumQueries(0):
+ prefetched_bookmarks = obj.favorite_bookmarks.all()
+ self.assertQuerySetEqual(prefetched_bookmarks, [second_bookmark])
+
class MultiTableInheritanceTest(TestCase):
@classmethod