3
3
import functools
4
4
import logging
5
5
6
+ import django
6
7
from django .core .cache .backends .base import DEFAULT_TIMEOUT
7
8
from django .db import models
8
9
from django .db .models import signals
9
- from django .db .models .sql import query , EmptyResultSet
10
+ from django .db .models .sql import EmptyResultSet , query
10
11
from django .utils import encoding
11
12
12
13
from caching import config
13
- from caching .invalidation import invalidator , flush_key , make_key , byid , cache
14
+ from caching .invalidation import byid , cache , flush_key , invalidator , make_key
14
15
15
16
try :
16
17
# ModelIterable is defined in Django 1.9+, and if it's present, we use it
@@ -30,7 +31,8 @@ def __iter__(self):
30
31
31
32
class CachingManager (models .Manager ):
32
33
33
- # Tell Django to use this manager when resolving foreign keys.
34
+ # This option removed in Django 2.0
35
+ # Tell Django to use this manager when resolving foreign keys. (Django < 2.0)
34
36
use_for_related_fields = True
35
37
36
38
def get_queryset (self ):
@@ -289,15 +291,25 @@ def _cache_keys(self, incl_db=True):
289
291
"""Return the cache key for self plus all related foreign keys."""
290
292
fks = dict ((f , getattr (self , f .attname )) for f in self ._meta .fields
291
293
if isinstance (f , models .ForeignKey ))
292
- keys = [fk .rel .to ._cache_key (val , incl_db and self ._state .db or None )
293
- for fk , val in list (fks .items ())
294
- if val is not None and hasattr (fk .rel .to , '_cache_key' )]
294
+
295
+ keys = []
296
+ for fk , val in list (fks .items ()):
297
+ related_model = self ._get_fk_related_model (fk )
298
+ if val is not None and hasattr (related_model , '_cache_key' ):
299
+ keys .append (related_model ._cache_key (val , incl_db and self ._state .db or None ))
300
+
295
301
return (self .get_cache_key (incl_db = incl_db ),) + tuple (keys )
296
302
297
303
def _flush_keys (self ):
298
304
"""Return the flush key for self plus all related foreign keys."""
299
305
return map (flush_key , self ._cache_keys (incl_db = False ))
300
306
307
+ def _get_fk_related_model (self , fk ):
308
+ if django .VERSION [0 ] >= 2 :
309
+ return fk .remote_field .model
310
+ else :
311
+ return fk .rel .to
312
+
301
313
302
314
class CachingRawQuerySet (models .query .RawQuerySet ):
303
315
@@ -311,7 +323,10 @@ def __iter__(self):
311
323
if self .timeout == config .NO_CACHE :
312
324
iterator = iterator ()
313
325
while True :
314
- yield next (iterator )
326
+ try :
327
+ yield next (iterator )
328
+ except StopIteration :
329
+ return
315
330
else :
316
331
for obj in CachingModelIterable (self , iter_function = iterator , timeout = self .timeout ):
317
332
yield obj
0 commit comments