mirror of
https://github.com/django/django.git
synced 2025-09-26 12:09:19 +00:00
Refs #16043 -- Refactored internal fields value cache.
* Removed all hardcoded logic for _{fieldname}_cache. * Added an internal API for interacting with the field values cache. Thanks carljm and MarkusH for support.
This commit is contained in:
parent
22ff86ec52
commit
bfb746f983
11 changed files with 156 additions and 107 deletions
|
@ -72,7 +72,7 @@ class ModelIterable(BaseIterable):
|
|||
if queryset._known_related_objects:
|
||||
for field, rel_objs in queryset._known_related_objects.items():
|
||||
# Avoid overwriting objects loaded e.g. by select_related
|
||||
if hasattr(obj, field.get_cache_name()):
|
||||
if field.is_cached(obj):
|
||||
continue
|
||||
pk = getattr(obj, field.get_attname())
|
||||
try:
|
||||
|
@ -1544,12 +1544,13 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
|
|||
# callable that gets value to be matched for returned instances,
|
||||
# callable that gets value to be matched for passed in instances,
|
||||
# boolean that is True for singly related objects,
|
||||
# cache name to assign to).
|
||||
# cache or field name to assign to,
|
||||
# boolean that is True when the previous argument is a cache name vs a field name).
|
||||
|
||||
# The 'values to be matched' must be hashable as they will be used
|
||||
# in a dictionary.
|
||||
|
||||
rel_qs, rel_obj_attr, instance_attr, single, cache_name = (
|
||||
rel_qs, rel_obj_attr, instance_attr, single, cache_name, is_descriptor = (
|
||||
prefetcher.get_prefetch_queryset(instances, lookup.get_current_queryset(level)))
|
||||
# We have to handle the possibility that the QuerySet we just got back
|
||||
# contains some prefetch_related lookups. We don't want to trigger the
|
||||
|
@ -1597,8 +1598,18 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
|
|||
|
||||
if single:
|
||||
val = vals[0] if vals else None
|
||||
to_attr = to_attr if as_attr else cache_name
|
||||
setattr(obj, to_attr, val)
|
||||
if as_attr:
|
||||
# A to_attr has been given for the prefetch.
|
||||
setattr(obj, to_attr, val)
|
||||
elif is_descriptor:
|
||||
# cache_name points to a field name in obj.
|
||||
# This field is a descriptor for a related object.
|
||||
setattr(obj, cache_name, val)
|
||||
else:
|
||||
# No to_attr has been given for this prefetch operation and the
|
||||
# cache_name does not point to a descriptor. Store the value of
|
||||
# the field in the object's field cache.
|
||||
obj._state.fields_cache[cache_name] = val
|
||||
else:
|
||||
if as_attr:
|
||||
setattr(obj, to_attr, vals)
|
||||
|
@ -1653,9 +1664,9 @@ class RelatedPopulator:
|
|||
# model's fields.
|
||||
# - related_populators: a list of RelatedPopulator instances if
|
||||
# select_related() descends to related models from this model.
|
||||
# - cache_name, reverse_cache_name: the names to use for setattr
|
||||
# when assigning the fetched object to the from_obj. If the
|
||||
# reverse_cache_name is set, then we also set the reverse link.
|
||||
# - field, remote_field: the fields to use for populating the
|
||||
# internal fields cache. If remote_field is set then we also
|
||||
# set the reverse link.
|
||||
select_fields = klass_info['select_fields']
|
||||
from_parent = klass_info['from_parent']
|
||||
if not from_parent:
|
||||
|
@ -1674,16 +1685,16 @@ class RelatedPopulator:
|
|||
self.model_cls = klass_info['model']
|
||||
self.pk_idx = self.init_list.index(self.model_cls._meta.pk.attname)
|
||||
self.related_populators = get_related_populators(klass_info, select, self.db)
|
||||
field = klass_info['field']
|
||||
reverse = klass_info['reverse']
|
||||
self.reverse_cache_name = None
|
||||
field = klass_info['field']
|
||||
self.remote_field = None
|
||||
if reverse:
|
||||
self.cache_name = field.remote_field.get_cache_name()
|
||||
self.reverse_cache_name = field.get_cache_name()
|
||||
self.field = field.remote_field
|
||||
self.remote_field = field
|
||||
else:
|
||||
self.cache_name = field.get_cache_name()
|
||||
self.field = field
|
||||
if field.unique:
|
||||
self.reverse_cache_name = field.remote_field.get_cache_name()
|
||||
self.remote_field = field.remote_field
|
||||
|
||||
def populate(self, row, from_obj):
|
||||
if self.reorder_for_init:
|
||||
|
@ -1697,9 +1708,9 @@ class RelatedPopulator:
|
|||
if obj and self.related_populators:
|
||||
for rel_iter in self.related_populators:
|
||||
rel_iter.populate(row, obj)
|
||||
setattr(from_obj, self.cache_name, obj)
|
||||
if obj and self.reverse_cache_name:
|
||||
setattr(obj, self.reverse_cache_name, from_obj)
|
||||
self.field.set_cached_value(from_obj, obj)
|
||||
if obj and self.remote_field:
|
||||
self.remote_field.set_cached_value(obj, from_obj)
|
||||
|
||||
|
||||
def get_related_populators(klass_info, select, db):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue