Ticket #13795: cache_key_prefix_13357.diff
File cache_key_prefix_13357.diff, 16.4 KB (added by , 14 years ago) |
---|
-
django/conf/global_settings.py
427 427 # The cache backend to use. See the docstring in django.core.cache for the 428 428 # possible values. 429 429 CACHE_BACKEND = 'locmem://' 430 CACHE_KEY_PREFIX = '' 430 431 CACHE_MIDDLEWARE_KEY_PREFIX = '' 431 432 CACHE_MIDDLEWARE_SECONDS = 600 432 433 -
django/core/cache/__init__.py
56 56 57 57 return scheme, host, params 58 58 59 def get_cache(backend_uri ):59 def get_cache(backend_uri, key_prefix=''): 60 60 scheme, host, params = parse_backend_uri(backend_uri) 61 61 if scheme in BACKENDS: 62 62 name = 'django.core.cache.backends.%s' % BACKENDS[scheme] 63 63 else: 64 64 name = scheme 65 65 module = importlib.import_module(name) 66 return getattr(module, 'CacheClass')(host, params )66 return getattr(module, 'CacheClass')(host, params, key_prefix) 67 67 68 cache = get_cache(settings.CACHE_BACKEND )68 cache = get_cache(settings.CACHE_BACKEND, settings.CACHE_KEY_PREFIX) 69 69 70 70 # Some caches -- pythont-memcached in particular -- need to do a cleanup at the 71 71 # end of a request cycle. If the cache provides a close() method, wire it up -
django/core/cache/backends/base.py
1 1 "Base Cache class." 2 2 3 3 from django.core.exceptions import ImproperlyConfigured 4 from django.utils.encoding import smart_str 4 5 5 6 class InvalidCacheBackendError(ImproperlyConfigured): 6 7 pass 7 8 8 9 class BaseCache(object): 9 def __init__(self, params ):10 def __init__(self, params, key_prefix=''): 10 11 timeout = params.get('timeout', 300) 11 12 try: 12 13 timeout = int(timeout) 13 14 except (ValueError, TypeError): 14 15 timeout = 300 15 16 self.default_timeout = timeout 17 self.key_prefix = smart_str(key_prefix) 16 18 19 def _key(self, key): 20 "Returns the key prepended with the `cache_prefix'." 21 return self.key_prefix + smart_str(key) 22 17 23 def add(self, key, value, timeout=None): 18 24 """ 19 25 Set a value in the cache if the key does not already exist. If -
django/core/cache/backends/locmem.py
10 10 from django.utils.synch import RWLock 11 11 12 12 class CacheClass(BaseCache): 13 def __init__(self, _, params ):14 BaseCache.__init__(self, params )13 def __init__(self, _, params, key_prefix): 14 BaseCache.__init__(self, params, key_prefix) 15 15 self._cache = {} 16 16 self._expire_info = {} 17 17 … … 30 30 self._lock = RWLock() 31 31 32 32 def add(self, key, value, timeout=None): 33 key = self._key(key) 33 34 self._lock.writer_enters() 34 35 try: 35 36 exp = self._expire_info.get(key) … … 44 45 self._lock.writer_leaves() 45 46 46 47 def get(self, key, default=None): 48 key = self._key(key) 47 49 self._lock.reader_enters() 48 50 try: 49 51 exp = self._expire_info.get(key) … … 76 78 self._expire_info[key] = time.time() + timeout 77 79 78 80 def set(self, key, value, timeout=None): 81 key = self._key(key) 79 82 self._lock.writer_enters() 80 83 # Python 2.4 doesn't allow combined try-except-finally blocks. 81 84 try: … … 87 90 self._lock.writer_leaves() 88 91 89 92 def has_key(self, key): 93 key = self._key(key) 90 94 self._lock.reader_enters() 91 95 try: 92 96 exp = self._expire_info.get(key) … … 127 131 pass 128 132 129 133 def delete(self, key): 134 key = self._key(key) 130 135 self._lock.writer_enters() 131 136 try: 132 137 self._delete(key) -
django/core/cache/backends/filebased.py
12 12 from django.utils.hashcompat import md5_constructor 13 13 14 14 class CacheClass(BaseCache): 15 def __init__(self, dir, params ):16 BaseCache.__init__(self, params )15 def __init__(self, dir, params, key_prefix): 16 BaseCache.__init__(self, params, key_prefix) 17 17 18 18 max_entries = params.get('max_entries', 300) 19 19 try: … … 32 32 self._createdir() 33 33 34 34 def add(self, key, value, timeout=None): 35 key = self._key(key) 35 36 if self.has_key(key): 36 37 return False 37 38 … … 39 40 return True 40 41 41 42 def get(self, key, default=None): 43 key = self._key(key) 42 44 fname = self._key_to_file(key) 43 45 try: 44 46 f = open(fname, 'rb') … … 56 58 return default 57 59 58 60 def set(self, key, value, timeout=None): 61 key = self._key(key) 59 62 fname = self._key_to_file(key) 60 63 dirname = os.path.dirname(fname) 61 64 … … 79 82 pass 80 83 81 84 def delete(self, key): 85 key = self._key(key) 82 86 try: 83 87 self._delete(self._key_to_file(key)) 84 88 except (IOError, OSError): … … 95 99 pass 96 100 97 101 def has_key(self, key): 102 key = self._key(key) 98 103 fname = self._key_to_file(key) 99 104 try: 100 105 f = open(fname, 'rb') … … 148 153 Thus, a cache key of "foo" gets turnned into a file named 149 154 ``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``. 150 155 """ 151 path = md5_constructor(key.encode('utf-8')).hexdigest() 156 key = self._key(key) 157 path = md5_constructor(key).hexdigest() 152 158 path = os.path.join(path[:2], path[2:4], path[4:]) 153 159 return os.path.join(self._dir, path) 154 160 -
django/core/cache/backends/db.py
10 10 import pickle 11 11 12 12 class CacheClass(BaseCache): 13 def __init__(self, table, params ):14 BaseCache.__init__(self, params )13 def __init__(self, table, params, key_prefix): 14 BaseCache.__init__(self, params, key_prefix) 15 15 self._table = connection.ops.quote_name(table) 16 16 max_entries = params.get('max_entries', 300) 17 17 try: … … 25 25 self._cull_frequency = 3 26 26 27 27 def get(self, key, default=None): 28 key = self._key(key) 28 29 cursor = connection.cursor() 29 30 cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key]) 30 31 row = cursor.fetchone() … … 45 46 return self._base_set('add', key, value, timeout) 46 47 47 48 def _base_set(self, mode, key, value, timeout=None): 49 key = self._key(key) 48 50 if timeout is None: 49 51 timeout = self.default_timeout 50 52 cursor = connection.cursor() … … 74 76 return True 75 77 76 78 def delete(self, key): 79 key = self._key(key) 77 80 cursor = connection.cursor() 78 81 cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key]) 79 82 transaction.commit_unless_managed() 80 83 81 84 def has_key(self, key): 85 key = self._key(key) 82 86 now = datetime.now().replace(microsecond=0) 83 87 cursor = connection.cursor() 84 88 cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % self._table, -
django/core/cache/backends/memcached.py
3 3 import time 4 4 5 5 from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError 6 from django.utils.encoding import smart_unicode, smart_str7 6 8 7 try: 9 8 import cmemcache as memcache … … 19 18 raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' or 'cmemcache' library") 20 19 21 20 class CacheClass(BaseCache): 22 def __init__(self, server, params ):23 BaseCache.__init__(self, params )21 def __init__(self, server, params, key_prefix): 22 BaseCache.__init__(self, params, key_prefix) 24 23 self._cache = memcache.Client(server.split(';')) 25 24 26 25 def _get_memcache_timeout(self, timeout): … … 40 39 return timeout 41 40 42 41 def add(self, key, value, timeout=0): 42 key = self._key(key) 43 43 if isinstance(value, unicode): 44 44 value = value.encode('utf-8') 45 return self._cache.add( smart_str(key), value, self._get_memcache_timeout(timeout))45 return self._cache.add(key, value, self._get_memcache_timeout(timeout)) 46 46 47 47 def get(self, key, default=None): 48 val = self._cache.get(smart_str(key)) 48 key = self._key(key) 49 val = self._cache.get(key) 49 50 if val is None: 50 51 return default 51 52 return val 52 53 53 54 def set(self, key, value, timeout=0): 54 self._cache.set(smart_str(key), value, self._get_memcache_timeout(timeout)) 55 key = self._key(key) 56 self._cache.set(key, value, self._get_memcache_timeout(timeout)) 55 57 56 58 def delete(self, key): 57 self._cache.delete(smart_str(key)) 59 key = self._key(key) 60 self._cache.delete(key) 58 61 59 62 def get_many(self, keys): 60 return self._cache.get_multi(map(smart_str,keys)) 63 keys = map(self._key, keys) 64 return self._cache.get_multi(keys) 61 65 62 66 def close(self, **kwargs): 63 67 self._cache.disconnect_all() 64 68 65 69 def incr(self, key, delta=1): 70 key = self._key(key) 66 71 try: 67 72 val = self._cache.incr(key, delta) 68 73 … … 77 82 return val 78 83 79 84 def decr(self, key, delta=1): 85 key = self._key(key) 80 86 try: 81 87 val = self._cache.decr(key, delta) 82 88 … … 92 98 def set_many(self, data, timeout=0): 93 99 safe_data = {} 94 100 for key, value in data.items(): 101 key = self._key(key) 95 102 if isinstance(value, unicode): 96 103 value = value.encode('utf-8') 97 safe_data[ smart_str(key)] = value104 safe_data[key] = value 98 105 self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout)) 99 106 100 107 def delete_many(self, keys): 101 self._cache.delete_multi(map(smart_str, keys)) 108 keys = map(self._key, keys) 109 self._cache.delete_multi(keys) 102 110 103 111 def clear(self): 104 112 self._cache.flush_all() -
tests/regressiontests/cache/tests.py
143 143 "clear does nothing for the dummy cache backend" 144 144 self.cache.clear() 145 145 146 class PrefixedDummyCacheTests(DummyCacheTests): 147 def setUp(self): 148 self.cache = get_cache('dummy://', 'dummy_prefix') 146 149 147 150 class BaseCacheTests(object): 148 151 # A common set of tests to apply to all cache backends … … 364 367 cursor = connection.cursor() 365 368 cursor.execute('DROP TABLE %s' % connection.ops.quote_name(self._table_name)) 366 369 370 class PrefixedDBCacheTests(DBCacheTests): 371 def setUp(self): 372 self._table_name = 'test cache table' 373 management.call_command('createcachetable', self._table_name, verbosity=0, interactive=False) 374 self.cache = get_cache('db://%s' % self._table_name, 'db_prefix') 375 367 376 class LocMemCacheTests(unittest.TestCase, BaseCacheTests): 368 377 def setUp(self): 369 378 self.cache = get_cache('locmem://') 370 379 380 class PrefixedLocMemCacheTests(LocMemCacheTests): 381 def setUp(self): 382 self.cache = get_cache('locmem://', 'locmem_prefix') 383 371 384 # memcached backend isn't guaranteed to be available. 372 385 # To check the memcached backend, the test settings file will 373 386 # need to contain a CACHE_BACKEND setting that points at … … 377 390 def setUp(self): 378 391 self.cache = get_cache(settings.CACHE_BACKEND) 379 392 393 class PrefixedMemcacheCacheTests(MemcachedCacheTests): 394 def setUp(self): 395 self.cache = get_cache(settings.CACHE_BACKEND, 'memcache_prefix') 396 380 397 class FileBasedCacheTests(unittest.TestCase, BaseCacheTests): 381 398 """ 382 399 Specific test cases for the file-based cache. … … 406 423 self.assert_(not os.path.exists(os.path.dirname(keypath))) 407 424 self.assert_(not os.path.exists(os.path.dirname(os.path.dirname(keypath)))) 408 425 426 class PrefixedFileBasedCacheTests(FileBasedCacheTests): 427 def setUp(self): 428 self.dirname = tempfile.mkdtemp() 429 self.cache = get_cache('file://%s' % self.dirname) 430 409 431 class CacheUtils(unittest.TestCase): 410 432 """TestCase for django.utils.cache functions.""" 411 433 412 434 def setUp(self): 413 435 self.path = '/cache/test/' 414 self.old_ settings_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX415 self.old_ middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS436 self.old_cache_middleware_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX 437 self.old_cache_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS 416 438 self.orig_use_i18n = settings.USE_I18N 417 439 settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix' 418 440 settings.CACHE_MIDDLEWARE_SECONDS = 1 419 441 settings.USE_I18N = False 420 442 421 443 def tearDown(self): 422 settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_ settings_key_prefix423 settings.CACHE_MIDDLEWARE_SECONDS = self.old_ middleware_seconds444 settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_cache_middleware_key_prefix 445 settings.CACHE_MIDDLEWARE_SECONDS = self.old_cache_middleware_seconds 424 446 settings.USE_I18N = self.orig_use_i18n 425 447 426 448 def _get_request(self, path): … … 473 495 learn_cache_key(request, response) 474 496 self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e') 475 497 498 class PrefixedCacheUtils(CacheUtils): 499 def setUp(self): 500 super(PrefixedCacheUtils, self).setUp() 501 self.old_cache_key_prefix = settings.CACHE_KEY_PREFIX 502 settings.CACHE_KEY_PREFIX = 'cacheprefix' 503 504 def tearDown(self): 505 super(PrefixedCacheUtils, self).tearDown() 506 settings.CACHE_KEY_PREFIX = self.old_cache_key_prefix 507 476 508 class CacheI18nTest(unittest.TestCase): 477 509 478 510 def setUp(self): … … 568 600 get_cache_data = FetchFromCacheMiddleware().process_request(request) 569 601 self.assertEqual(get_cache_data.content, es_message) 570 602 603 class PrefixedCacheI18nTest(CacheI18nTest): 604 def setUp(self): 605 super(PrefixedCacheI18nTest, self).setUp() 606 self.old_cache_key_prefix = settings.CACHE_KEY_PREFIX 607 settings.CACHE_KEY_PREFIX = 'cacheprefix' 608 609 def tearDown(self): 610 super(PrefixedCacheI18nTest, self).tearDown() 611 settings.CACHE_KEY_PREFIX = self.old_cache_key_prefix 612 571 613 if __name__ == '__main__': 572 614 unittest.main() -
docs/topics/cache.txt
600 600 However, if the backend doesn't natively provide an increment/decrement 601 601 operation, it will be implemented using a two-step retrieve/update. 602 602 603 CACHE_KEY_PREFIX 604 ---------------- 605 606 It is a common occurence to have a shared cache instance running on your development 607 or production server for use across multiple projects, i.e. all sites are pointing 608 to the memcached instance running on port 11211. As a result, cache key conflicts 609 may arise which could result in data from one site being used by another. 610 611 To alleviate this, CACHE_KEY_PREFIX can be set. This will be prepended to all keys 612 that are used with the cache backend, transparently:: 613 614 # in settings, CACHE_KEY_PREFIX = 'myproject_' 615 616 >>> cache.set('my_key', 'hello world!') # set with key 'myproject_my_key' 617 >>> cache.get('my_key') # retrieved with key 'myproject_my_key' 618 'hello world!' 619 620 Of course, for sites that _do_ share content, simply set the CACHE_KEY_PREFIX for 621 both sites to the same value. The default value for CACHE_KEY_PREFIX is the empty 622 string ``''``. 623 603 624 Upstream caches 604 625 =============== 605 626