diff options
Diffstat (limited to 'django/db/models/fields/related_descriptors.py')
| -rw-r--r-- | django/db/models/fields/related_descriptors.py | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index 3e2150e0f6..2c8e59f1d9 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -78,7 +78,7 @@ from django.db.models.expressions import ColPairs from django.db.models.fields.tuple_lookups import TupleIn from django.db.models.functions import RowNumber from django.db.models.lookups import GreaterThan, LessThanOrEqual -from django.db.models.query import QuerySet +from django.db.models.query import QuerySet, prefetch_related_objects from django.db.models.query_utils import DeferredAttribute from django.db.models.utils import AltersData, resolve_callables from django.utils.functional import cached_property @@ -254,13 +254,9 @@ class ForwardManyToOneDescriptor: break if rel_obj is None and has_value: - rel_obj = self.get_object(instance) - remote_field = self.field.remote_field - # If this is a one-to-one relation, set the reverse accessor - # cache on the related object to the current instance to avoid - # an extra SQL query if it's accessed later on. - if not remote_field.multiple: - remote_field.set_cached_value(rel_obj, instance) + instance._state.fetch_mode.fetch(self, instance) + return self.field.get_cached_value(instance) + self.field.set_cached_value(instance, rel_obj) if rel_obj is None and not self.field.null: @@ -270,6 +266,21 @@ class ForwardManyToOneDescriptor: else: return rel_obj + def fetch_one(self, instance): + rel_obj = self.get_object(instance) + self.field.set_cached_value(instance, rel_obj) + # If this is a one-to-one relation, set the reverse accessor cache on + # the related object to the current instance to avoid an extra SQL + # query if it's accessed later on. + remote_field = self.field.remote_field + if not remote_field.multiple: + remote_field.set_cached_value(rel_obj, instance) + + def fetch_many(self, instances): + is_cached = self.is_cached + missing_instances = [i for i in instances if not is_cached(i)] + prefetch_related_objects(missing_instances, self.field.name) + def __set__(self, instance, value): """ Set the related instance through the forward relation. @@ -504,16 +515,8 @@ class ReverseOneToOneDescriptor: if not instance._is_pk_set(): rel_obj = None else: - filter_args = self.related.field.get_forward_related_filter(instance) - try: - rel_obj = self.get_queryset(instance=instance).get(**filter_args) - except self.related.related_model.DoesNotExist: - rel_obj = None - else: - # Set the forward accessor cache on the related object to - # the current instance to avoid an extra SQL query if it's - # accessed later on. - self.related.field.set_cached_value(rel_obj, instance) + instance._state.fetch_mode.fetch(self, instance) + rel_obj = self.related.get_cached_value(instance) self.related.set_cached_value(instance, rel_obj) if rel_obj is None: @@ -524,6 +527,34 @@ class ReverseOneToOneDescriptor: else: return rel_obj + @property + def field(self): + """ + Add compatibility with the fetcher protocol. While self.related is not + a field but a OneToOneRel, it quacks enough like a field to work. + """ + return self.related + + def fetch_one(self, instance): + # Kept for backwards compatibility with overridden + # get_forward_related_filter() + filter_args = self.related.field.get_forward_related_filter(instance) + try: + rel_obj = self.get_queryset(instance=instance).get(**filter_args) + except self.related.related_model.DoesNotExist: + rel_obj = None + else: + self.related.field.set_cached_value(rel_obj, instance) + self.related.set_cached_value(instance, rel_obj) + + def fetch_many(self, instances): + is_cached = self.is_cached + missing_instances = [i for i in instances if not is_cached(i)] + prefetch_related_objects( + missing_instances, + self.related.get_accessor_name(), + ) + def __set__(self, instance, value): """ Set the related instance through the reverse relation. |
