summaryrefslogtreecommitdiff
path: root/django/contrib/contenttypes
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2025-01-25 00:12:17 -0500
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-02-03 09:39:14 +0000
commit198b30168d4e94af42e0dc7967bd3259b5c5790b (patch)
treea97f5178482b76824a0d4e4279442360fecd2a1f /django/contrib/contenttypes
parentd15454a6e84a595ffc8dc1b926282f484f782a8f (diff)
Fixed #36135 -- Fixed reverse GenericRelation prefetching.
The get_(local|foreign)_related_value methods of GenericRelation must be reversed because it defines (from|to)_fields and associated related_fields in the reversed order as it's effectively a reverse GenericForeignKey itself. The related value methods must also account for the fact that referenced primary key values might be stored as a string on the model defining the GenericForeignKey but as integer on the model defining the GenericRelation. This is achieved by calling the to_python method of the involved content type in get_foreign_related_value just like GenericRelatedObjectManager does. Lastly reverse many-to-one manager's prefetch_related_querysets should use set_cached_value instead of direct attribute assignment as direct assignment might are disallowed on ReverseManyToOneDescriptor descriptors. This is likely something that was missed in f5233dc (refs #32511) when the is_cached guard was added. Thanks 1xinghuan for the report.
Diffstat (limited to 'django/contrib/contenttypes')
-rw-r--r--django/contrib/contenttypes/fields.py14
1 files changed, 14 insertions, 0 deletions
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index 0e68c2eef0..272cb2b02c 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -389,6 +389,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.