1010import logging
1111import types
1212
13- import django .db .models
1413from django .conf import settings
1514from django .core .exceptions import FieldDoesNotExist
1615from django .db import models
@@ -77,26 +76,36 @@ def _is_reverse_relation(field):
7776 return isinstance (field , ForeignObjectRel )
7877
7978
80- def _cache_related_instance (inst , field_name , model_cache ):
79+ def _get_callable_field_value_with_cache (inst , field_name , model_cache , field_type ):
80+ cache_relation = True
81+
8182 try :
8283 field_meta = inst ._meta .get_field (field_name )
84+ if not _is_relation (field_meta ) or _is_reverse_relation (field_meta ):
85+ # no `attname` in reverse relations
86+ cache_relation = False
8387 except (AttributeError , FieldDoesNotExist ):
84- return
85- if not _is_relation (field_meta ) or _is_reverse_relation (field_meta ):
86- return # no `attname` in reverse relations
87- val_pk = getattr (inst , field_meta .attname )
88- val_cls = field_meta .related_model
89- cache_key = _make_model_cache_key (val_cls , val_pk )
88+ cache_relation = False
89+
90+ if cache_relation :
91+ val_pk = getattr (inst , field_meta .attname )
92+ val_cls = field_meta .related_model
93+ cache_key = _make_model_cache_key (val_cls , val_pk )
94+ else :
95+ cache_key = (inst , field_name )
96+
9097 if cache_key in model_cache :
9198 logger .debug ("ev=model_cache, status=hit, key=%s" , cache_key )
92- related_instance = model_cache [cache_key ]
99+ result = model_cache [cache_key ]
93100 else :
94101 logger .debug ("ev=model_cache, status=miss, key=%s" , cache_key )
95- related_instance = getattr (inst , field_name )
96- if not isinstance (related_instance , val_cls ):
97- return
98- model_cache [cache_key ] = related_instance
99- setattr (inst , field_name , related_instance )
102+ result = field_type (inst )
103+
104+ if isinstance (result , models .Manager ):
105+ # need to get an iterable to proceed
106+ result = result .all ()
107+ model_cache [cache_key ] = result
108+ return result
100109
101110
102111def _get_filtered_field_value ( # noqa: C901
@@ -114,9 +123,12 @@ def _get_filtered_field_value( # noqa: C901
114123 return None
115124
116125 if isinstance (field_type , types .FunctionType ):
117- val = field_type (inst )
118- if is_caching_enabled () and isinstance (val , django .db .models .Model ):
119- _cache_related_instance (inst , field_name , model_cache )
126+ if is_caching_enabled ():
127+ val = _get_callable_field_value_with_cache (
128+ inst , field_name , model_cache , field_type
129+ )
130+ else :
131+ val = field_type (inst )
120132 elif isinstance (field_type , _ExpandableForeignKey ):
121133 if expand_this :
122134 inst_field_name = field_type .inst_field_name or field_name
0 commit comments