Code

Ticket #7338: method_cache_with_invalidation_r9787.diff

File method_cache_with_invalidation_r9787.diff, 5.2 KB (added by msaelices, 5 years ago)

Caching with manager invalidation

Line 
1Index: django/db/models/sql/query.py
2===================================================================
3--- django/db/models/sql/query.py       (revisión: 9787)
4+++ django/db/models/sql/query.py       (copia de trabajo)
5@@ -19,6 +19,7 @@
6 from django.db.models.query_utils import select_related_descend
7 from django.db.models.sql import aggregates as base_aggregates_module
8 from django.db.models.sql.where import WhereNode, Constraint, EverythingNode, AND, OR
9+from django.core.cache import cache
10 from django.core.exceptions import FieldError
11 from datastructures import EmptyResultSet, Empty, MultiJoin
12 from constants import *
13@@ -90,6 +91,10 @@
14         self.extra_params = ()
15         self.extra_order_by = ()
16 
17+        # Cached queryset atribute. None means no cached
18+        self.cache_timeout = None
19+        self.cache_key = None
20+
21     def __str__(self):
22         """
23         Returns the query as a string of SQL with the parameter values
24@@ -190,6 +195,8 @@
25         obj.extra_where = self.extra_where
26         obj.extra_params = self.extra_params
27         obj.extra_order_by = self.extra_order_by
28+        obj.cache_timeout = self.cache_timeout
29+        obj.cache_key = self.cache_key
30         if self.filter_is_sticky and self.used_aliases:
31             obj.used_aliases = self.used_aliases.copy()
32         else:
33@@ -237,7 +244,33 @@
34         """
35         resolve_columns = hasattr(self, 'resolve_columns')
36         fields = None
37-        for rows in self.execute_sql(MULTI):
38+        if self.cache_timeout is not None:
39+            # Check cache for stored objects from an exactly equal query
40+            k = str(self)
41+            try:
42+                import hashlib
43+            except ImportError:
44+                import sha
45+                k = sha.new(k).hexdigest()
46+            else:
47+                k = hashlib.sha1(k).hexdigest()
48+
49+            self.cache_key = k
50+
51+            if cache.has_key(k) and cache.get(k):
52+                sql_result = cache.get(k, [])
53+            else:
54+                cache.set(k, [i for i in self.execute_sql(MULTI)], self.cache_timeout)
55+                sql_result = cache.get(k, [])
56+                # register this cache key for allowing later invalidation
57+                model_cache_key = self.model._meta.cache_key
58+                cache_register = cache.get(model_cache_key, [])
59+                cache_register.append(k)
60+                cache.set(model_cache_key, cache_register)
61+        else:
62+            sql_result = self.execute_sql(MULTI)
63+
64+        for rows in sql_result:
65             for row in rows:
66                 if resolve_columns:
67                     if fields is None:
68Index: django/db/models/manager.py
69===================================================================
70--- django/db/models/manager.py (revisión: 9787)
71+++ django/db/models/manager.py (copia de trabajo)
72@@ -3,6 +3,7 @@
73 from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
74 from django.db.models import signals
75 from django.db.models.fields import FieldDoesNotExist
76+from django.core.cache import cache
77 
78 def ensure_default_manager(sender, **kwargs):
79     cls = sender
80@@ -140,6 +141,16 @@
81     def reverse(self, *args, **kwargs):
82         return self.get_query_set().reverse(*args, **kwargs)
83 
84+    def cache(self, timeout=20):
85+        return self.get_query_set().cache(timeout=timeout)
86+
87+    def flush_cache(self):
88+        model_cache_key = self.model._meta.cache_key
89+        cache_register = cache.get(model_cache_key, [])
90+        for cached_queryset_key in cache_register:
91+            cache.delete(cached_queryset_key)
92+        cache.delete(model_cache_key)
93+
94     def _insert(self, values, **kwargs):
95         return insert_query(self.model, values, **kwargs)
96 
97Index: django/db/models/options.py
98===================================================================
99--- django/db/models/options.py (revisión: 9787)
100+++ django/db/models/options.py (copia de trabajo)
101@@ -44,6 +44,7 @@
102         self.abstract = False
103         self.parents = SortedDict()
104         self.duplicate_targets = {}
105+        self.cache_key = None
106         # Managers that have been inherited from abstract base classes. These
107         # are passed onto any children.
108         self.abstract_managers = []
109@@ -58,6 +59,7 @@
110         self.object_name = cls.__name__
111         self.module_name = self.object_name.lower()
112         self.verbose_name = get_verbose_name(self.object_name)
113+        self.cache_key = 'modelcache-%s.%s' % (self.app_label, self.module_name)
114 
115         # Next, apply any overridden values from 'class Meta'.
116         if self.meta:
117Index: django/db/models/query.py
118===================================================================
119--- django/db/models/query.py   (revisión: 9787)
120+++ django/db/models/query.py   (copia de trabajo)
121@@ -640,6 +640,16 @@
122         clone.query.standard_ordering = not clone.query.standard_ordering
123         return clone
124 
125+    def cache(self, timeout=20):
126+        """
127+        Forces the current queryset to check if a exact equal query has been
128+        stored in the cache. The expiration time is the seconds in 'timeout'
129+        variable.
130+        """
131+        clone = self._clone()
132+        clone.query.cache_timeout = timeout
133+        return clone
134+
135     ###################
136     # PRIVATE METHODS #
137     ###################