11"Database cache backend."
22
33from django .core .cache .backends .base import BaseCache
4- from django .db import connection , transaction , DatabaseError
4+ from django .db import connections , router , transaction , DatabaseError
55import base64 , time
66from datetime import datetime
77try :
88 import cPickle as pickle
99except ImportError :
1010 import pickle
1111
12+ class Options (object ):
13+ """A class that will quack like a Django model _meta class.
14+
15+ This allows cache operations to be controlled by the router
16+ """
17+ def __init__ (self , table ):
18+ self .db_table = table
19+ self .app_label = 'django_cache'
20+ self .module_name = 'cacheentry'
21+ self .verbose_name = 'cache entry'
22+ self .verbose_name_plural = 'cache entries'
23+ self .object_name = 'CacheEntry'
24+ self .abstract = False
25+ self .managed = True
26+ self .proxy = False
27+
1228class CacheClass (BaseCache ):
1329 def __init__ (self , table , params ):
1430 BaseCache .__init__ (self , params )
15- self ._table = connection .ops .quote_name (table )
31+ self ._table = table
32+
33+ class CacheEntry (object ):
34+ _meta = Options (table )
35+ self .cache_model_class = CacheEntry
36+
1637 max_entries = params .get ('max_entries' , 300 )
1738 try :
1839 self ._max_entries = int (max_entries )
@@ -25,17 +46,22 @@ def __init__(self, table, params):
2546 self ._cull_frequency = 3
2647
2748 def get (self , key , default = None ):
28- cursor = connection .cursor ()
29- cursor .execute ("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self ._table , [key ])
49+ db = router .db_for_read (self .cache_model_class )
50+ table = connections [db ].ops .quote_name (self ._table )
51+ cursor = connections [db ].cursor ()
52+
53+ cursor .execute ("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % table , [key ])
3054 row = cursor .fetchone ()
3155 if row is None :
3256 return default
3357 now = datetime .now ()
3458 if row [2 ] < now :
35- cursor .execute ("DELETE FROM %s WHERE cache_key = %%s" % self ._table , [key ])
36- transaction .commit_unless_managed ()
59+ db = router .db_for_write (self .cache_model_class )
60+ cursor = connections [db ].cursor ()
61+ cursor .execute ("DELETE FROM %s WHERE cache_key = %%s" % table , [key ])
62+ transaction .commit_unless_managed (using = db )
3763 return default
38- value = connection .ops .process_clob (row [1 ])
64+ value = connections [ db ] .ops .process_clob (row [1 ])
3965 return pickle .loads (base64 .decodestring (value ))
4066
4167 def set (self , key , value , timeout = None ):
@@ -47,56 +73,67 @@ def add(self, key, value, timeout=None):
4773 def _base_set (self , mode , key , value , timeout = None ):
4874 if timeout is None :
4975 timeout = self .default_timeout
50- cursor = connection .cursor ()
51- cursor .execute ("SELECT COUNT(*) FROM %s" % self ._table )
76+ db = router .db_for_write (self .cache_model_class )
77+ table = connections [db ].ops .quote_name (self ._table )
78+ cursor = connections [db ].cursor ()
79+
80+ cursor .execute ("SELECT COUNT(*) FROM %s" % table )
5281 num = cursor .fetchone ()[0 ]
5382 now = datetime .now ().replace (microsecond = 0 )
5483 exp = datetime .fromtimestamp (time .time () + timeout ).replace (microsecond = 0 )
5584 if num > self ._max_entries :
56- self ._cull (cursor , now )
85+ self ._cull (db , cursor , now )
5786 encoded = base64 .encodestring (pickle .dumps (value , 2 )).strip ()
58- cursor .execute ("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % self . _table , [key ])
87+ cursor .execute ("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % table , [key ])
5988 try :
6089 result = cursor .fetchone ()
6190 if result and (mode == 'set' or
6291 (mode == 'add' and result [1 ] < now )):
63- cursor .execute ("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self . _table ,
64- [encoded , connection .ops .value_to_db_datetime (exp ), key ])
92+ cursor .execute ("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % table ,
93+ [encoded , connections [ db ] .ops .value_to_db_datetime (exp ), key ])
6594 else :
66- cursor .execute ("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self . _table ,
67- [key , encoded , connection .ops .value_to_db_datetime (exp )])
95+ cursor .execute ("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % table ,
96+ [key , encoded , connections [ db ] .ops .value_to_db_datetime (exp )])
6897 except DatabaseError :
6998 # To be threadsafe, updates/inserts are allowed to fail silently
70- transaction .rollback_unless_managed ()
99+ transaction .rollback_unless_managed (using = db )
71100 return False
72101 else :
73- transaction .commit_unless_managed ()
102+ transaction .commit_unless_managed (using = db )
74103 return True
75104
76105 def delete (self , key ):
77- cursor = connection .cursor ()
78- cursor .execute ("DELETE FROM %s WHERE cache_key = %%s" % self ._table , [key ])
79- transaction .commit_unless_managed ()
106+ db = router .db_for_write (self .cache_model_class )
107+ table = connections [db ].ops .quote_name (self ._table )
108+ cursor = connections [db ].cursor ()
109+
110+ cursor .execute ("DELETE FROM %s WHERE cache_key = %%s" % table , [key ])
111+ transaction .commit_unless_managed (using = db )
80112
81113 def has_key (self , key ):
114+ db = router .db_for_read (self .cache_model_class )
115+ table = connections [db ].ops .quote_name (self ._table )
116+ cursor = connections [db ].cursor ()
117+
82118 now = datetime .now ().replace (microsecond = 0 )
83- cursor = connection .cursor ()
84- cursor .execute ("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % self ._table ,
85- [key , connection .ops .value_to_db_datetime (now )])
119+ cursor .execute ("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % table ,
120+ [key , connections [db ].ops .value_to_db_datetime (now )])
86121 return cursor .fetchone () is not None
87122
88- def _cull (self , cursor , now ):
123+ def _cull (self , db , cursor , now ):
89124 if self ._cull_frequency == 0 :
90125 self .clear ()
91126 else :
92- cursor .execute ("DELETE FROM %s WHERE expires < %%s" % self . _table ,
93- [connection .ops .value_to_db_datetime (now )])
94- cursor .execute ("SELECT COUNT(*) FROM %s" % self . _table )
127+ cursor .execute ("DELETE FROM %s WHERE expires < %%s" % table ,
128+ [connections [ db ] .ops .value_to_db_datetime (now )])
129+ cursor .execute ("SELECT COUNT(*) FROM %s" % table )
95130 num = cursor .fetchone ()[0 ]
96131 if num > self ._max_entries :
97- cursor .execute ("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % self . _table , [num / self ._cull_frequency ])
98- cursor .execute ("DELETE FROM %s WHERE cache_key < %%s" % self . _table , [cursor .fetchone ()[0 ]])
132+ cursor .execute ("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % table , [num / self ._cull_frequency ])
133+ cursor .execute ("DELETE FROM %s WHERE cache_key < %%s" % table , [cursor .fetchone ()[0 ]])
99134
100135 def clear (self ):
101- cursor = connection .cursor ()
102- cursor .execute ('DELETE FROM %s' % self ._table )
136+ db = router .db_for_write (self .cache_model_class )
137+ table = connections [db ].ops .quote_name (self ._table )
138+ cursor = connections [db ].cursor ()
139+ cursor .execute ('DELETE FROM %s' % table )
0 commit comments