From 5e80390add100e0c7a1ac8e51739f94c5d706ea3 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 19 Feb 2024 04:47:12 +0000 Subject: [PATCH] Fixed #35230 -- Added cached ForeignObjectRel.accessor_name. --- django/contrib/admindocs/views.py | 2 +- django/db/models/fields/related.py | 10 +++++----- django/db/models/fields/related_descriptors.py | 8 ++++---- django/db/models/fields/reverse_related.py | 6 +++++- tests/one_to_one/tests.py | 4 +--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 5c18d676f2b7..38a2bb9286ff 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -359,7 +359,7 @@ def get_context_data(self, **kwargs): "app_label": rel.related_model._meta.app_label, "object_name": rel.related_model._meta.object_name, } - accessor = rel.get_accessor_name() + accessor = rel.accessor_name fields.append( { "name": "%s.all" % accessor, diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 8564e6366b17..1628e46d2c2c 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -254,7 +254,7 @@ def _check_clashes(self): # (so `is_hidden` returns True), then there are no clashes to check # and we can skip these fields. rel_is_hidden = self.remote_field.is_hidden() - rel_name = self.remote_field.get_accessor_name() # i. e. "model_set" + rel_name = self.remote_field.accessor_name # i. e. "model_set" rel_query_name = self.related_query_name() # i. e. "model" # i.e. "app_label.Model.field". field_name = "%s.%s" % (opts.label, self.name) @@ -307,7 +307,7 @@ def _check_clashes(self): clash_field.related_model._meta.label, clash_field.field.name, ) - if not rel_is_hidden and clash_field.get_accessor_name() == rel_name: + if not rel_is_hidden and clash_field.accessor_name == rel_name: errors.append( checks.Error( f"Reverse accessor '{rel_opts.object_name}.{rel_name}' " @@ -323,7 +323,7 @@ def _check_clashes(self): ) ) - if clash_field.get_accessor_name() == rel_query_name: + if clash_field.accessor_name == rel_query_name: errors.append( checks.Error( "Reverse query name for '%s' clashes with reverse query name " @@ -893,7 +893,7 @@ def contribute_to_related_class(self, cls, related): ): setattr( cls._meta.concrete_model, - related.get_accessor_name(), + related.accessor_name, self.related_accessor_class(related), ) # While 'limit_choices_to' might be a callable, simply pass @@ -1947,7 +1947,7 @@ def contribute_to_related_class(self, cls, related): ): setattr( cls, - related.get_accessor_name(), + related.accessor_name, ManyToManyDescriptor(self.remote_field, reverse=True), ) diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index a8f298230ab2..9269cdb10082 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -524,7 +524,7 @@ def __get__(self, instance, cls=None): if rel_obj is None: raise self.RelatedObjectDoesNotExist( "%s has no %s." - % (instance.__class__.__name__, self.related.get_accessor_name()) + % (instance.__class__.__name__, self.related.accessor_name) ) else: return rel_obj @@ -564,7 +564,7 @@ def __set__(self, instance, value): % ( value, instance._meta.object_name, - self.related.get_accessor_name(), + self.related.accessor_name, self.related.related_model._meta.object_name, ) ) @@ -652,7 +652,7 @@ def __get__(self, instance, cls=None): def _get_set_deprecation_msg_params(self): return ( "reverse side of a related set", - self.rel.get_accessor_name(), + self.rel.accessor_name, ) def __set__(self, instance, value): @@ -1019,7 +1019,7 @@ def _get_set_deprecation_msg_params(self): return ( "%s side of a many-to-many set" % ("reverse" if self.reverse else "forward"), - self.rel.get_accessor_name() if self.reverse else self.field.name, + self.rel.accessor_name if self.reverse else self.field.name, ) diff --git a/django/db/models/fields/reverse_related.py b/django/db/models/fields/reverse_related.py index 144cce6142c7..9d357a3948d2 100644 --- a/django/db/models/fields/reverse_related.py +++ b/django/db/models/fields/reverse_related.py @@ -219,6 +219,10 @@ def set_field_name(self): # example custom multicolumn joins currently have no remote field). self.field_name = None + @cached_property + def accessor_name(self): + return self.get_accessor_name() + def get_accessor_name(self, model=None): # This method encapsulates the logic that decides what name to give an # accessor descriptor that retrieves related many-to-one or @@ -252,7 +256,7 @@ def get_cache_name(self): Return the name of the cache key to use for storing an instance of the forward model on the reverse model. """ - return self.get_accessor_name() + return self.accessor_name class ManyToOneRel(ForeignObjectRel): diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py index 83644871feb4..280a8273fb18 100644 --- a/tests/one_to_one/tests.py +++ b/tests/one_to_one/tests.py @@ -473,9 +473,7 @@ def test_hidden_accessor(self): self.assertFalse( hasattr( Target, - HiddenPointer._meta.get_field( - "target" - ).remote_field.get_accessor_name(), + HiddenPointer._meta.get_field("target").remote_field.accessor_name, ) )