mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #21012 -- Thread-local caches, like databases.
This commit is contained in:
		
				
					committed by
					
						 Aymeric Augustin
						Aymeric Augustin
					
				
			
			
				
	
			
			
			
						parent
						
							3ca0815c0b
						
					
				
				
					commit
					ee7eb0f73e
				
			| @@ -1,6 +1,6 @@ | |||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.contrib.sessions.backends.base import SessionBase, CreateError | from django.contrib.sessions.backends.base import SessionBase, CreateError | ||||||
| from django.core.cache import get_cache | from django.core.cache import caches | ||||||
| from django.utils.six.moves import xrange | from django.utils.six.moves import xrange | ||||||
|  |  | ||||||
| KEY_PREFIX = "django.contrib.sessions.cache" | KEY_PREFIX = "django.contrib.sessions.cache" | ||||||
| @@ -11,7 +11,7 @@ class SessionStore(SessionBase): | |||||||
|     A cache-based session store. |     A cache-based session store. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, session_key=None): |     def __init__(self, session_key=None): | ||||||
|         self._cache = get_cache(settings.SESSION_CACHE_ALIAS) |         self._cache = caches[settings.SESSION_CACHE_ALIAS] | ||||||
|         super(SessionStore, self).__init__(session_key) |         super(SessionStore, self).__init__(session_key) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import logging | |||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.contrib.sessions.backends.db import SessionStore as DBStore | from django.contrib.sessions.backends.db import SessionStore as DBStore | ||||||
| from django.core.cache import get_cache | from django.core.cache import caches | ||||||
| from django.core.exceptions import SuspiciousOperation | from django.core.exceptions import SuspiciousOperation | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.utils.encoding import force_text | from django.utils.encoding import force_text | ||||||
| @@ -20,7 +20,7 @@ class SessionStore(DBStore): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, session_key=None): |     def __init__(self, session_key=None): | ||||||
|         self._cache = get_cache(settings.SESSION_CACHE_ALIAS) |         self._cache = caches[settings.SESSION_CACHE_ALIAS] | ||||||
|         super(SessionStore, self).__init__(session_key) |         super(SessionStore, self).__init__(session_key) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ from django.contrib.sessions.backends.file import SessionStore as FileSession | |||||||
| from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession | from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession | ||||||
| from django.contrib.sessions.models import Session | from django.contrib.sessions.models import Session | ||||||
| from django.contrib.sessions.middleware import SessionMiddleware | from django.contrib.sessions.middleware import SessionMiddleware | ||||||
| from django.core.cache import get_cache | from django.core.cache import caches | ||||||
| from django.core.cache.backends.base import InvalidCacheBackendError | from django.core.cache.backends.base import InvalidCacheBackendError | ||||||
| from django.core import management | from django.core import management | ||||||
| from django.core.exceptions import ImproperlyConfigured | from django.core.exceptions import ImproperlyConfigured | ||||||
| @@ -140,7 +140,7 @@ class SessionTestsMixin(object): | |||||||
|         self.assertTrue(self.session.modified) |         self.assertTrue(self.session.modified) | ||||||
|  |  | ||||||
|     def test_save(self): |     def test_save(self): | ||||||
|         if (hasattr(self.session, '_cache') and'DummyCache' in |         if (hasattr(self.session, '_cache') and 'DummyCache' in | ||||||
|             settings.CACHES[settings.SESSION_CACHE_ALIAS]['BACKEND']): |             settings.CACHES[settings.SESSION_CACHE_ALIAS]['BACKEND']): | ||||||
|             raise unittest.SkipTest("Session saving tests require a real cache backend") |             raise unittest.SkipTest("Session saving tests require a real cache backend") | ||||||
|         self.session.save() |         self.session.save() | ||||||
| @@ -481,7 +481,7 @@ class CacheSessionTests(SessionTestsMixin, unittest.TestCase): | |||||||
|  |  | ||||||
|     def test_default_cache(self): |     def test_default_cache(self): | ||||||
|         self.session.save() |         self.session.save() | ||||||
|         self.assertNotEqual(get_cache('default').get(self.session.cache_key), None) |         self.assertNotEqual(caches['default'].get(self.session.cache_key), None) | ||||||
|  |  | ||||||
|     @override_settings(CACHES={ |     @override_settings(CACHES={ | ||||||
|         'default': { |         'default': { | ||||||
| @@ -489,6 +489,7 @@ class CacheSessionTests(SessionTestsMixin, unittest.TestCase): | |||||||
|         }, |         }, | ||||||
|         'sessions': { |         'sessions': { | ||||||
|             'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', |             'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', | ||||||
|  |             'LOCATION': 'session', | ||||||
|         }, |         }, | ||||||
|     }, SESSION_CACHE_ALIAS='sessions') |     }, SESSION_CACHE_ALIAS='sessions') | ||||||
|     def test_non_default_cache(self): |     def test_non_default_cache(self): | ||||||
| @@ -496,8 +497,8 @@ class CacheSessionTests(SessionTestsMixin, unittest.TestCase): | |||||||
|         self.session = self.backend() |         self.session = self.backend() | ||||||
|  |  | ||||||
|         self.session.save() |         self.session.save() | ||||||
|         self.assertEqual(get_cache('default').get(self.session.cache_key), None) |         self.assertEqual(caches['default'].get(self.session.cache_key), None) | ||||||
|         self.assertNotEqual(get_cache('sessions').get(self.session.cache_key), None) |         self.assertNotEqual(caches['sessions'].get(self.session.cache_key), None) | ||||||
|  |  | ||||||
|  |  | ||||||
| class SessionMiddlewareTests(unittest.TestCase): | class SessionMiddlewareTests(unittest.TestCase): | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ import posixpath | |||||||
| import re | import re | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core.cache import (get_cache, InvalidCacheBackendError, | from django.core.cache import (caches, InvalidCacheBackendError, | ||||||
|                                cache as default_cache) |                                cache as default_cache) | ||||||
| from django.core.exceptions import ImproperlyConfigured | from django.core.exceptions import ImproperlyConfigured | ||||||
| from django.core.files.base import ContentFile | from django.core.files.base import ContentFile | ||||||
| @@ -56,7 +56,7 @@ class CachedFilesMixin(object): | |||||||
|     def __init__(self, *args, **kwargs): |     def __init__(self, *args, **kwargs): | ||||||
|         super(CachedFilesMixin, self).__init__(*args, **kwargs) |         super(CachedFilesMixin, self).__init__(*args, **kwargs) | ||||||
|         try: |         try: | ||||||
|             self.cache = get_cache('staticfiles') |             self.cache = caches['staticfiles'] | ||||||
|         except InvalidCacheBackendError: |         except InvalidCacheBackendError: | ||||||
|             # Use the default backend |             # Use the default backend | ||||||
|             self.cache = default_cache |             self.cache = default_cache | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								django/core/cache/__init__.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										139
									
								
								django/core/cache/__init__.py
									
									
									
									
										vendored
									
									
								
							| @@ -14,6 +14,9 @@ class. | |||||||
|  |  | ||||||
| See docs/topics/cache.txt for information on the public API. | See docs/topics/cache.txt for information on the public API. | ||||||
| """ | """ | ||||||
|  | from threading import local | ||||||
|  | import warnings | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core import signals | from django.core import signals | ||||||
| from django.core.cache.backends.base import ( | from django.core.cache.backends.base import ( | ||||||
| @@ -23,8 +26,8 @@ from django.utils.module_loading import import_by_path | |||||||
|  |  | ||||||
|  |  | ||||||
| __all__ = [ | __all__ = [ | ||||||
|     'get_cache', 'cache', 'DEFAULT_CACHE_ALIAS', 'InvalidCacheBackendError', |     'create_cache', 'get_cache', 'cache', 'DEFAULT_CACHE_ALIAS', | ||||||
|     'CacheKeyWarning', 'BaseCache', |     'InvalidCacheBackendError', 'CacheKeyWarning', 'BaseCache', | ||||||
| ] | ] | ||||||
|  |  | ||||||
| DEFAULT_CACHE_ALIAS = 'default' | DEFAULT_CACHE_ALIAS = 'default' | ||||||
| @@ -35,43 +38,61 @@ if DEFAULT_CACHE_ALIAS not in settings.CACHES: | |||||||
|  |  | ||||||
| def get_cache(backend, **kwargs): | def get_cache(backend, **kwargs): | ||||||
|     """ |     """ | ||||||
|     Function to load a cache backend dynamically. This is flexible by design |     Function to retrieve a configure cache, or create a new one. | ||||||
|     to allow different use cases: |  | ||||||
|  |  | ||||||
|     To load a backend that is pre-defined in the settings:: |     This wrapper is for backward compatibility. | ||||||
|  |  | ||||||
|         cache = get_cache('default') |     Use either create_cache or caches directly. | ||||||
|  |  | ||||||
|     To load a backend with its dotted import path, |  | ||||||
|     including arbitrary options:: |  | ||||||
|  |  | ||||||
|         cache = get_cache('django.core.cache.backends.memcached.MemcachedCache', **{ |  | ||||||
|             'LOCATION': '127.0.0.1:11211', 'TIMEOUT': 30, |  | ||||||
|         }) |  | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |     warnings.warn("'get_cache' is deprecated.  Use either caches or create_cache.", | ||||||
|  |         PendingDeprecationWarning, stacklevel=2) | ||||||
|  |  | ||||||
|  |     # If it's just an alias with no options, use the new API | ||||||
|  |     if backend in settings.CACHES and not kwargs: | ||||||
|  |         return caches[backend] | ||||||
|  |  | ||||||
|  |     return create_cache(backend, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def create_cache(backend, **params): | ||||||
|  |     """ | ||||||
|  |     Function to create a cache backend dynamically.  This is flexible by design | ||||||
|  |     to allow different use cases: | ||||||
|  |  | ||||||
|  |     To load a backend with its dotted import path, including options:: | ||||||
|  |  | ||||||
|  |         cache = get_cache('django.core.cache.backends.memcached.MemcachedCache', | ||||||
|  |             LOCATION='127.0.0.1:11211', TIMEOUT=30, | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |     To create a new instance of a cache in settings.CACHES, pass the alias:: | ||||||
|  |  | ||||||
|  |         cache = create_cache('default') | ||||||
|  |  | ||||||
|  |     You can also pass extra parameters to override those in settings.CACHES:: | ||||||
|  |  | ||||||
|  |         cache = create_cache('default', LOCATION='bar') | ||||||
|  |  | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     # We can name a cache from settings.CACHES and update its params | ||||||
|  |     try: | ||||||
|  |         conf = settings.CACHES[backend] | ||||||
|  |     except KeyError: | ||||||
|  |         pass | ||||||
|  |     else: | ||||||
|  |         params = conf.copy() | ||||||
|  |         params.update(params) | ||||||
|  |         backend = params.pop('BACKEND') | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         # Try to get the CACHES entry for the given backend name first |  | ||||||
|         try: |  | ||||||
|             conf = settings.CACHES[backend] |  | ||||||
|         except KeyError: |  | ||||||
|             try: |  | ||||||
|                 # Trying to import the given backend, in case it's a dotted path |  | ||||||
|                 import_by_path(backend) |  | ||||||
|             except ImproperlyConfigured as e: |  | ||||||
|                 raise InvalidCacheBackendError("Could not find backend '%s': %s" % ( |  | ||||||
|                     backend, e)) |  | ||||||
|             location = kwargs.pop('LOCATION', '') |  | ||||||
|             params = kwargs |  | ||||||
|         else: |  | ||||||
|             params = conf.copy() |  | ||||||
|             params.update(kwargs) |  | ||||||
|             backend = params.pop('BACKEND') |  | ||||||
|             location = params.pop('LOCATION', '') |  | ||||||
|         backend_cls = import_by_path(backend) |         backend_cls = import_by_path(backend) | ||||||
|     except (AttributeError, ImportError, ImproperlyConfigured) as e: |     except ImproperlyConfigured as e: | ||||||
|         raise InvalidCacheBackendError( |         raise InvalidCacheBackendError("Could not find backend '%s': %s" % ( | ||||||
|             "Could not find backend '%s': %s" % (backend, e)) |             backend, e | ||||||
|  |         )) | ||||||
|  |     location = params.pop('LOCATION', '') | ||||||
|     cache = backend_cls(location, params) |     cache = backend_cls(location, params) | ||||||
|     # Some caches -- python-memcached in particular -- need to do a cleanup at the |     # Some caches -- python-memcached in particular -- need to do a cleanup at the | ||||||
|     # end of a request cycle. If not implemented in a particular backend |     # end of a request cycle. If not implemented in a particular backend | ||||||
| @@ -79,4 +100,54 @@ def get_cache(backend, **kwargs): | |||||||
|     signals.request_finished.connect(cache.close) |     signals.request_finished.connect(cache.close) | ||||||
|     return cache |     return cache | ||||||
|  |  | ||||||
| cache = get_cache(DEFAULT_CACHE_ALIAS) |  | ||||||
|  | class CacheHandler(object): | ||||||
|  |     """ | ||||||
|  |     A Cache Handler to manage access to Cache instances. | ||||||
|  |  | ||||||
|  |     Ensures only one instance of each alias exists per thread. | ||||||
|  |     """ | ||||||
|  |     def __init__(self): | ||||||
|  |         self._caches = local() | ||||||
|  |  | ||||||
|  |     def __getitem__(self, alias): | ||||||
|  |         try: | ||||||
|  |             return getattr(self._caches, alias) | ||||||
|  |         except AttributeError: | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         if alias not in settings.CACHES: | ||||||
|  |             raise InvalidCacheBackendError( | ||||||
|  |                 "Could not find config for '%s' in settings.CACHES" % alias | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         cache = create_cache(alias) | ||||||
|  |         setattr(self._caches, alias, cache) | ||||||
|  |  | ||||||
|  |         return cache | ||||||
|  |  | ||||||
|  | caches = CacheHandler() | ||||||
|  |  | ||||||
|  | class DefaultCacheProxy(object): | ||||||
|  |     """ | ||||||
|  |     Proxy access to the default Cache object's attributes. | ||||||
|  |  | ||||||
|  |     This allows the legacy `cache` object to be thread-safe using the new | ||||||
|  |     ``caches`` API. | ||||||
|  |     """ | ||||||
|  |     def __getattr__(self, name): | ||||||
|  |         return getattr(caches[DEFAULT_CACHE_ALIAS], name) | ||||||
|  |  | ||||||
|  |     def __setattr__(self, name, value): | ||||||
|  |         return setattr(caches[DEFAULT_CACHE_ALIAS], name, value) | ||||||
|  |  | ||||||
|  |     def __delattr__(self, name): | ||||||
|  |         return delattr(caches[DEFAULT_CACHE_ALIAS], name) | ||||||
|  |  | ||||||
|  |     def __eq__(self, other): | ||||||
|  |         return caches[DEFAULT_CACHE_ALIAS] == other | ||||||
|  |  | ||||||
|  |     def __ne__(self, other): | ||||||
|  |         return caches[DEFAULT_CACHE_ALIAS] != other | ||||||
|  |  | ||||||
|  | cache = DefaultCacheProxy() | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								django/core/cache/backends/memcached.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								django/core/cache/backends/memcached.py
									
									
									
									
										vendored
									
									
								
							| @@ -2,13 +2,13 @@ | |||||||
|  |  | ||||||
| import time | import time | ||||||
| import pickle | import pickle | ||||||
| from threading import local |  | ||||||
|  |  | ||||||
| from django.core.cache.backends.base import BaseCache, DEFAULT_TIMEOUT | from django.core.cache.backends.base import BaseCache, DEFAULT_TIMEOUT | ||||||
|  |  | ||||||
| from django.utils import six | from django.utils import six | ||||||
| from django.utils.deprecation import RenameMethodsBase | from django.utils.deprecation import RenameMethodsBase | ||||||
| from django.utils.encoding import force_str | from django.utils.encoding import force_str | ||||||
|  | from django.utils.functional import cached_property | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseMemcachedCacheMethods(RenameMethodsBase): | class BaseMemcachedCacheMethods(RenameMethodsBase): | ||||||
| @@ -177,24 +177,14 @@ class PyLibMCCache(BaseMemcachedCache): | |||||||
|     "An implementation of a cache binding using pylibmc" |     "An implementation of a cache binding using pylibmc" | ||||||
|     def __init__(self, server, params): |     def __init__(self, server, params): | ||||||
|         import pylibmc |         import pylibmc | ||||||
|         self._local = local() |  | ||||||
|         super(PyLibMCCache, self).__init__(server, params, |         super(PyLibMCCache, self).__init__(server, params, | ||||||
|                                            library=pylibmc, |                                            library=pylibmc, | ||||||
|                                            value_not_found_exception=pylibmc.NotFound) |                                            value_not_found_exception=pylibmc.NotFound) | ||||||
|  |  | ||||||
|     @property |     @cached_property | ||||||
|     def _cache(self): |     def _cache(self): | ||||||
|         # PylibMC uses cache options as the 'behaviors' attribute. |  | ||||||
|         # It also needs to use threadlocals, because some versions of |  | ||||||
|         # PylibMC don't play well with the GIL. |  | ||||||
|         client = getattr(self._local, 'client', None) |  | ||||||
|         if client: |  | ||||||
|             return client |  | ||||||
|  |  | ||||||
|         client = self._lib.Client(self._servers) |         client = self._lib.Client(self._servers) | ||||||
|         if self._options: |         if self._options: | ||||||
|             client.behaviors = self._options |             client.behaviors = self._options | ||||||
|  |  | ||||||
|         self._local.client = client |  | ||||||
|  |  | ||||||
|         return client |         return client | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| from optparse import make_option | from optparse import make_option | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core.cache import get_cache | from django.core.cache import create_cache | ||||||
| from django.core.cache.backends.db import BaseDatabaseCache | from django.core.cache.backends.db import BaseDatabaseCache | ||||||
| from django.core.management.base import BaseCommand, CommandError | from django.core.management.base import BaseCommand, CommandError | ||||||
| from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS | from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS | ||||||
| @@ -30,7 +30,7 @@ class Command(BaseCommand): | |||||||
|                 self.create_table(db, tablename) |                 self.create_table(db, tablename) | ||||||
|         else: |         else: | ||||||
|             for cache_alias in settings.CACHES: |             for cache_alias in settings.CACHES: | ||||||
|                 cache = get_cache(cache_alias) |                 cache = create_cache(cache_alias) | ||||||
|                 if isinstance(cache, BaseDatabaseCache): |                 if isinstance(cache, BaseDatabaseCache): | ||||||
|                     self.create_table(db, cache._table) |                     self.create_table(db, cache._table) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ More details about how the caching works: | |||||||
| import warnings | import warnings | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS | from django.core.cache import create_cache, caches, DEFAULT_CACHE_ALIAS | ||||||
| from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age | from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -64,7 +64,7 @@ class UpdateCacheMiddleware(object): | |||||||
|         self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |         self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX | ||||||
|         self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |         self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) | ||||||
|         self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS |         self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS | ||||||
|         self.cache = get_cache(self.cache_alias) |         self.cache = caches[self.cache_alias] | ||||||
|  |  | ||||||
|     def _session_accessed(self, request): |     def _session_accessed(self, request): | ||||||
|         try: |         try: | ||||||
| @@ -122,10 +122,9 @@ class FetchFromCacheMiddleware(object): | |||||||
|     MIDDLEWARE_CLASSES so that it'll get called last during the request phase. |     MIDDLEWARE_CLASSES so that it'll get called last during the request phase. | ||||||
|     """ |     """ | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |  | ||||||
|         self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |         self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX | ||||||
|         self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS |         self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS | ||||||
|         self.cache = get_cache(self.cache_alias) |         self.cache = caches[self.cache_alias] | ||||||
|  |  | ||||||
|     def process_request(self, request): |     def process_request(self, request): | ||||||
|         """ |         """ | ||||||
| @@ -169,39 +168,32 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware): | |||||||
|         # we fall back to system defaults. If it is not provided at all, |         # we fall back to system defaults. If it is not provided at all, | ||||||
|         # we need to use middleware defaults. |         # we need to use middleware defaults. | ||||||
|  |  | ||||||
|         cache_kwargs = {} |         try: | ||||||
|  |             key_prefix = kwargs['key_prefix'] | ||||||
|  |             if key_prefix is None: | ||||||
|  |                 key_prefix = '' | ||||||
|  |         except KeyError: | ||||||
|  |             key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX | ||||||
|  |         self.key_prefix = key_prefix | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             self.key_prefix = kwargs['key_prefix'] |             cache_alias = kwargs['cache_alias'] | ||||||
|             if self.key_prefix is not None: |             if cache_alias is None: | ||||||
|                 cache_kwargs['KEY_PREFIX'] = self.key_prefix |                 cache_alias = DEFAULT_CACHE_ALIAS | ||||||
|             else: |  | ||||||
|                 self.key_prefix = '' |  | ||||||
|         except KeyError: |         except KeyError: | ||||||
|             self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |             cache_alias = settings.CACHE_MIDDLEWARE_ALIAS | ||||||
|             cache_kwargs['KEY_PREFIX'] = self.key_prefix |         self.cache_alias = cache_alias | ||||||
|  |  | ||||||
|         try: |         if cache_timeout is None: | ||||||
|             self.cache_alias = kwargs['cache_alias'] |             cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS | ||||||
|             if self.cache_alias is None: |         self.cache_timeout = cache_timeout | ||||||
|                 self.cache_alias = DEFAULT_CACHE_ALIAS |  | ||||||
|             if cache_timeout is not None: |  | ||||||
|                 cache_kwargs['TIMEOUT'] = cache_timeout |  | ||||||
|         except KeyError: |  | ||||||
|             self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS |  | ||||||
|             if cache_timeout is None: |  | ||||||
|                 cache_kwargs['TIMEOUT'] = settings.CACHE_MIDDLEWARE_SECONDS |  | ||||||
|             else: |  | ||||||
|                 cache_kwargs['TIMEOUT'] = cache_timeout |  | ||||||
|  |  | ||||||
|         if cache_anonymous_only is None: |         if cache_anonymous_only is None: | ||||||
|             self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |             cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) | ||||||
|         else: |         self.cache_anonymous_only = cache_anonymous_only | ||||||
|             self.cache_anonymous_only = cache_anonymous_only |  | ||||||
|  |  | ||||||
|         if self.cache_anonymous_only: |         if self.cache_anonymous_only: | ||||||
|             msg = "CACHE_MIDDLEWARE_ANONYMOUS_ONLY has been deprecated and will be removed in Django 1.8." |             msg = "CACHE_MIDDLEWARE_ANONYMOUS_ONLY has been deprecated and will be removed in Django 1.8." | ||||||
|             warnings.warn(msg, DeprecationWarning, stacklevel=1) |             warnings.warn(msg, DeprecationWarning, stacklevel=1) | ||||||
|  |  | ||||||
|         self.cache = get_cache(self.cache_alias, **cache_kwargs) |         self.cache = create_cache(self.cache_alias) | ||||||
|         self.cache_timeout = self.cache.default_timeout |  | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
| from django.core.cache import get_cache, InvalidCacheBackendError | from django.core.cache import caches, InvalidCacheBackendError | ||||||
| from django.core.cache.utils import make_template_fragment_key | from django.core.cache.utils import make_template_fragment_key | ||||||
| from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist | from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist | ||||||
|  |  | ||||||
| register = Library() | register = Library() | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     default_cache = get_cache('template_fragments') |     default_cache = caches['template_fragments'] | ||||||
| except InvalidCacheBackendError: | except InvalidCacheBackendError: | ||||||
|     from django.core.cache import cache as default_cache |     from django.core.cache import cache as default_cache | ||||||
|  |  | ||||||
| @@ -35,7 +35,7 @@ class CacheNode(Node): | |||||||
|             except VariableDoesNotExist: |             except VariableDoesNotExist: | ||||||
|                 raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var) |                 raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var) | ||||||
|             try: |             try: | ||||||
|                 cache = get_cache(cache_name) |                 cache = caches[cache_name] | ||||||
|             except InvalidCacheBackendError: |             except InvalidCacheBackendError: | ||||||
|                 raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name) |                 raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name) | ||||||
|         else: |         else: | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import re | |||||||
| import time | import time | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core.cache import get_cache | from django.core.cache import caches | ||||||
| from django.utils.encoding import iri_to_uri, force_bytes, force_text | from django.utils.encoding import iri_to_uri, force_bytes, force_text | ||||||
| from django.utils.http import http_date | from django.utils.http import http_date | ||||||
| from django.utils.timezone import get_current_timezone_name | from django.utils.timezone import get_current_timezone_name | ||||||
| @@ -219,7 +219,7 @@ def get_cache_key(request, key_prefix=None, method='GET', cache=None): | |||||||
|         key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |         key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX | ||||||
|     cache_key = _generate_cache_header_key(key_prefix, request) |     cache_key = _generate_cache_header_key(key_prefix, request) | ||||||
|     if cache is None: |     if cache is None: | ||||||
|         cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS) |         cache = caches[settings.CACHE_MIDDLEWARE_ALIAS] | ||||||
|     headerlist = cache.get(cache_key, None) |     headerlist = cache.get(cache_key, None) | ||||||
|     if headerlist is not None: |     if headerlist is not None: | ||||||
|         return _generate_cache_key(request, method, headerlist, key_prefix) |         return _generate_cache_key(request, method, headerlist, key_prefix) | ||||||
| @@ -246,7 +246,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cach | |||||||
|         cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |         cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS | ||||||
|     cache_key = _generate_cache_header_key(key_prefix, request) |     cache_key = _generate_cache_header_key(key_prefix, request) | ||||||
|     if cache is None: |     if cache is None: | ||||||
|         cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS) |         cache = caches[settings.CACHE_MIDDLEWARE_ALIAS] | ||||||
|     if response.has_header('Vary'): |     if response.has_header('Vary'): | ||||||
|         is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N |         is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N | ||||||
|         # If i18n or l10n are used, the generated cache key will be suffixed |         # If i18n or l10n are used, the generated cache key will be suffixed | ||||||
|   | |||||||
| @@ -215,6 +215,9 @@ these changes. | |||||||
|  |  | ||||||
| * The internal ``django.utils.functional.memoize`` will be removed. | * The internal ``django.utils.functional.memoize`` will be removed. | ||||||
|  |  | ||||||
|  | * ``get_cache`` from django.core.cache will be removed.  Instead, use | ||||||
|  |   ``create_cache`` or  ``caches``, depending on your need. | ||||||
|  |  | ||||||
| 2.0 | 2.0 | ||||||
| --- | --- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -269,6 +269,26 @@ Minor features | |||||||
|   allowing the ``published`` element to be included in the feed (which |   allowing the ``published`` element to be included in the feed (which | ||||||
|   relies on ``pubdate``). |   relies on ``pubdate``). | ||||||
|  |  | ||||||
|  | Cache | ||||||
|  | ^^^^^ | ||||||
|  |  | ||||||
|  | * Access to caches configured in ``settings.CACHES`` is now available via | ||||||
|  |   ``django.core.cache.caches``.  This will now return a different instance per | ||||||
|  |   thread. | ||||||
|  |  | ||||||
|  | * A new function ``django.core.cache.create_cache`` has been added to make it | ||||||
|  |   clearer what's happening.  ``django.core.cache.get_cache`` will call this | ||||||
|  |   if it's passed anything other than just a cache config alias. | ||||||
|  |  | ||||||
|  | * ``django.core.cache.get_cache`` has been deprecated.  Use | ||||||
|  |   ``django.core.cache.caches`` to access caches configurd in | ||||||
|  |   ``settings.CACHES``, or ``django.core.cache.create_cache`` to create ad-hoc | ||||||
|  |   instances. | ||||||
|  |  | ||||||
|  | * All thread safety in cache backends has been removed, as | ||||||
|  |   ``django.core.cache.caches`` now yields differend backend instances per | ||||||
|  |    thread. | ||||||
|  |  | ||||||
| Email | Email | ||||||
| ^^^^^ | ^^^^^ | ||||||
|  |  | ||||||
| @@ -643,6 +663,12 @@ Miscellaneous | |||||||
| Features deprecated in 1.7 | Features deprecated in 1.7 | ||||||
| ========================== | ========================== | ||||||
|  |  | ||||||
|  | ``django.core.cache.get_cache`` | ||||||
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | ``django.core.cache.get_cache`` has been supplanted by | ||||||
|  | ``django.core.cache.caches`` and ``django.core.cache.create_cache``. | ||||||
|  |  | ||||||
| ``django.utils.dictconfig``/``django.utils.importlib`` | ``django.utils.dictconfig``/``django.utils.importlib`` | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -703,7 +703,22 @@ pickling.) | |||||||
| Accessing the cache | Accessing the cache | ||||||
| ------------------- | ------------------- | ||||||
|  |  | ||||||
| .. function:: django.core.cache.get_cache(backend, **kwargs) | .. versionadded:: 1.7 | ||||||
|  |  | ||||||
|  | You can access the caches configured in ``settings.CACHES`` through the | ||||||
|  | dict-like ``django.core.cache.caches`` object. Repeated requests for the same | ||||||
|  | alias will return the same object. | ||||||
|  |  | ||||||
|  |     >>> from django.core.cache import caches | ||||||
|  |     >>> cache1 = caches['myalias'] | ||||||
|  |     >>> cache2 = caches['myalias'] | ||||||
|  |     >>> cache1 is cache2 | ||||||
|  |     True | ||||||
|  |  | ||||||
|  | If the named key does not exist, ``InvalidCacheBackendError`` will be raised. | ||||||
|  |  | ||||||
|  | The ``caches`` dict is thread aware, so a different instance of each alias will | ||||||
|  | be returned for each thread. | ||||||
|  |  | ||||||
| The cache module, ``django.core.cache``, has a ``cache`` object that's | The cache module, ``django.core.cache``, has a ``cache`` object that's | ||||||
| automatically created from the ``'default'`` entry in the :setting:`CACHES` | automatically created from the ``'default'`` entry in the :setting:`CACHES` | ||||||
| @@ -711,13 +726,43 @@ setting:: | |||||||
|  |  | ||||||
|     >>> from django.core.cache import cache |     >>> from django.core.cache import cache | ||||||
|  |  | ||||||
| If you have multiple caches defined in :setting:`CACHES`, then you can use | This is a proxy object to caches['default']. It is provided for backward | ||||||
| :func:`django.core.cache.get_cache` to retrieve a cache object for any key:: | compatiblity. | ||||||
|  |  | ||||||
|  | .. function:: django.core.cache.create_cache(backend, **kwargs) | ||||||
|  |  | ||||||
|  | You can create caches from ad-hoc configurations using ``create_cache``. | ||||||
|  |  | ||||||
|  |     >>> from django.core.cache import create_cache | ||||||
|  |     # Create an instance of a specific backend | ||||||
|  |     >>> cache = create_cache( | ||||||
|  |         'django.core.cache.backends.memcached.MemcachedCache', | ||||||
|  |         LOCATION='/tmp/memcached.sock' | ||||||
|  |     ) | ||||||
|  |     # Create a separate copy of the 'default' cache: | ||||||
|  |     >>> new_default = create_cache('default') | ||||||
|  |     # Create a cache with the same config as 'default', but a different timeout | ||||||
|  |     >>> cache2 = create_cache('default', TIMEOUT=1) | ||||||
|  |  | ||||||
|  | This is guaranteed to always create a new instance. | ||||||
|  |  | ||||||
|  | .. function:: django.core.cache.get_cache(backend, **kwargs) | ||||||
|  |  | ||||||
|  | .. deprecated:: 1.7 | ||||||
|  |     This function has been deprecated in favour of ``caches`` and | ||||||
|  |     ``create_cache``. | ||||||
|  |  | ||||||
|  | Before Django 1.7 this was the only way to get a cache instance.  Now it acts | ||||||
|  | as a wrapper to ``create_cache``, except in the case where it is passed only a | ||||||
|  | configured alias, where it will return the cache from ``caches``:: | ||||||
|  |  | ||||||
|     >>> from django.core.cache import get_cache |     >>> from django.core.cache import get_cache | ||||||
|     >>> cache = get_cache('alternate') |     # Passes call to create_cache | ||||||
|  |     >>> cache = get_cache('django.core.cache.backends.memcached.MemcachedCache', LOCATION='127.0.0.2') | ||||||
| If the named key does not exist, ``InvalidCacheBackendError`` will be raised. |     # Creates a new cache based on the config in settings.CACHES['default'] | ||||||
|  |     >>> cache = get_cache('default', TIMEOUT=300) | ||||||
|  |     # Returns instance from caches object | ||||||
|  |     >>> cache = get_cache('default') | ||||||
|  |  | ||||||
|  |  | ||||||
| Basic usage | Basic usage | ||||||
|   | |||||||
							
								
								
									
										118
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							| @@ -10,13 +10,14 @@ import random | |||||||
| import re | import re | ||||||
| import string | import string | ||||||
| import tempfile | import tempfile | ||||||
|  | import threading | ||||||
| import time | import time | ||||||
| import unittest | import unittest | ||||||
| import warnings | import warnings | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core import management | from django.core import management | ||||||
| from django.core.cache import get_cache | from django.core.cache import create_cache, caches | ||||||
| from django.core.cache.backends.base import (CacheKeyWarning, | from django.core.cache.backends.base import (CacheKeyWarning, | ||||||
|     InvalidCacheBackendError) |     InvalidCacheBackendError) | ||||||
| from django.db import connection, router, transaction | from django.db import connection, router, transaction | ||||||
| @@ -55,7 +56,7 @@ class DummyCacheTests(unittest.TestCase): | |||||||
|     backend_name = 'django.core.cache.backends.dummy.DummyCache' |     backend_name = 'django.core.cache.backends.dummy.DummyCache' | ||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.cache = get_cache(self.backend_name) |         self.cache = create_cache(self.backend_name) | ||||||
|  |  | ||||||
|     def test_simple(self): |     def test_simple(self): | ||||||
|         "Dummy cache backend ignores cache set calls" |         "Dummy cache backend ignores cache set calls" | ||||||
| @@ -840,11 +841,11 @@ class DBCacheTests(BaseCacheTests, TransactionTestCase): | |||||||
|         # Spaces are used in the table name to ensure quoting/escaping is working |         # Spaces are used in the table name to ensure quoting/escaping is working | ||||||
|         self._table_name = 'test cache table' |         self._table_name = 'test cache table' | ||||||
|         management.call_command('createcachetable', verbosity=0, interactive=False) |         management.call_command('createcachetable', verbosity=0, interactive=False) | ||||||
|         self.cache = get_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30}) |         self.cache = create_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30}) | ||||||
|         self.prefix_cache = get_cache(self.backend_name, LOCATION=self._table_name, KEY_PREFIX='cacheprefix') |         self.prefix_cache = create_cache(self.backend_name, LOCATION=self._table_name, KEY_PREFIX='cacheprefix') | ||||||
|         self.v2_cache = get_cache(self.backend_name, LOCATION=self._table_name, VERSION=2) |         self.v2_cache = create_cache(self.backend_name, LOCATION=self._table_name, VERSION=2) | ||||||
|         self.custom_key_cache = get_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION=custom_key_func) |         self.custom_key_cache = create_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION=custom_key_func) | ||||||
|         self.custom_key_cache2 = get_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION='cache.tests.custom_key_func') |         self.custom_key_cache2 = create_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION='cache.tests.custom_key_func') | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         cursor = connection.cursor() |         cursor = connection.cursor() | ||||||
| @@ -855,7 +856,7 @@ class DBCacheTests(BaseCacheTests, TransactionTestCase): | |||||||
|         self.perform_cull_test(50, 29) |         self.perform_cull_test(50, 29) | ||||||
|  |  | ||||||
|     def test_zero_cull(self): |     def test_zero_cull(self): | ||||||
|         self.cache = get_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) |         self.cache = create_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) | ||||||
|         self.perform_cull_test(50, 18) |         self.perform_cull_test(50, 18) | ||||||
|  |  | ||||||
|     def test_second_call_doesnt_crash(self): |     def test_second_call_doesnt_crash(self): | ||||||
| @@ -950,11 +951,11 @@ class LocMemCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|         self.cache = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}) |         self.cache = create_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}) | ||||||
|         self.prefix_cache = get_cache(self.backend_name, KEY_PREFIX='cacheprefix') |         self.prefix_cache = create_cache(self.backend_name, KEY_PREFIX='cacheprefix') | ||||||
|         self.v2_cache = get_cache(self.backend_name, VERSION=2) |         self.v2_cache = create_cache(self.backend_name, VERSION=2) | ||||||
|         self.custom_key_cache = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION=custom_key_func) |         self.custom_key_cache = create_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION=custom_key_func) | ||||||
|         self.custom_key_cache2 = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION='cache.tests.custom_key_func') |         self.custom_key_cache2 = create_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION='cache.tests.custom_key_func') | ||||||
|  |  | ||||||
|         # LocMem requires a hack to make the other caches |         # LocMem requires a hack to make the other caches | ||||||
|         # share a data store with the 'normal' cache. |         # share a data store with the 'normal' cache. | ||||||
| @@ -977,13 +978,13 @@ class LocMemCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|         self.perform_cull_test(50, 29) |         self.perform_cull_test(50, 29) | ||||||
|  |  | ||||||
|     def test_zero_cull(self): |     def test_zero_cull(self): | ||||||
|         self.cache = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) |         self.cache = create_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) | ||||||
|         self.perform_cull_test(50, 19) |         self.perform_cull_test(50, 19) | ||||||
|  |  | ||||||
|     def test_multiple_caches(self): |     def test_multiple_caches(self): | ||||||
|         "Check that multiple locmem caches are isolated" |         "Check that multiple locmem caches are isolated" | ||||||
|         mirror_cache = get_cache(self.backend_name) |         mirror_cache = create_cache(self.backend_name) | ||||||
|         other_cache = get_cache(self.backend_name, LOCATION='other') |         other_cache = create_cache(self.backend_name, LOCATION='other') | ||||||
|  |  | ||||||
|         self.cache.set('value1', 42) |         self.cache.set('value1', 42) | ||||||
|         self.assertEqual(mirror_cache.get('value1'), 42) |         self.assertEqual(mirror_cache.get('value1'), 42) | ||||||
| @@ -1017,11 +1018,11 @@ class MemcachedCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|             if cache['BACKEND'].startswith('django.core.cache.backends.memcached.'): |             if cache['BACKEND'].startswith('django.core.cache.backends.memcached.'): | ||||||
|                 break |                 break | ||||||
|         random_prefix = ''.join(random.choice(string.ascii_letters) for x in range(10)) |         random_prefix = ''.join(random.choice(string.ascii_letters) for x in range(10)) | ||||||
|         self.cache = get_cache(cache_key) |         self.cache = caches[cache_key] | ||||||
|         self.prefix_cache = get_cache(cache_key, KEY_PREFIX=random_prefix) |         self.prefix_cache = create_cache(cache_key, KEY_PREFIX=random_prefix) | ||||||
|         self.v2_cache = get_cache(cache_key, VERSION=2) |         self.v2_cache = create_cache(cache_key, VERSION=2) | ||||||
|         self.custom_key_cache = get_cache(cache_key, KEY_FUNCTION=custom_key_func) |         self.custom_key_cache = create_cache(cache_key, KEY_FUNCTION=custom_key_func) | ||||||
|         self.custom_key_cache2 = get_cache(cache_key, KEY_FUNCTION='cache.tests.custom_key_func') |         self.custom_key_cache2 = create_cache(cache_key, KEY_FUNCTION='cache.tests.custom_key_func') | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         self.cache.clear() |         self.cache.clear() | ||||||
| @@ -1050,7 +1051,7 @@ class MemcachedCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|         # Regression test for #19810 |         # Regression test for #19810 | ||||||
|         for cache_key, cache in settings.CACHES.items(): |         for cache_key, cache in settings.CACHES.items(): | ||||||
|             if cache['BACKEND'] == 'django.core.cache.backends.memcached.MemcachedCache': |             if cache['BACKEND'] == 'django.core.cache.backends.memcached.MemcachedCache': | ||||||
|                 self.assertEqual(get_cache(cache_key)._cache.pickleProtocol, |                 self.assertEqual(caches[cache_key]._cache.pickleProtocol, | ||||||
|                                  pickle.HIGHEST_PROTOCOL) |                                  pickle.HIGHEST_PROTOCOL) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1063,11 +1064,11 @@ class FileBasedCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|         self.dirname = tempfile.mkdtemp() |         self.dirname = tempfile.mkdtemp() | ||||||
|         self.cache = get_cache(self.backend_name, LOCATION=self.dirname, OPTIONS={'MAX_ENTRIES': 30}) |         self.cache = create_cache(self.backend_name, LOCATION=self.dirname, OPTIONS={'MAX_ENTRIES': 30}) | ||||||
|         self.prefix_cache = get_cache(self.backend_name, LOCATION=self.dirname, KEY_PREFIX='cacheprefix') |         self.prefix_cache = create_cache(self.backend_name, LOCATION=self.dirname, KEY_PREFIX='cacheprefix') | ||||||
|         self.v2_cache = get_cache(self.backend_name, LOCATION=self.dirname, VERSION=2) |         self.v2_cache = create_cache(self.backend_name, LOCATION=self.dirname, VERSION=2) | ||||||
|         self.custom_key_cache = get_cache(self.backend_name, LOCATION=self.dirname, KEY_FUNCTION=custom_key_func) |         self.custom_key_cache = create_cache(self.backend_name, LOCATION=self.dirname, KEY_FUNCTION=custom_key_func) | ||||||
|         self.custom_key_cache2 = get_cache(self.backend_name, LOCATION=self.dirname, KEY_FUNCTION='cache.tests.custom_key_func') |         self.custom_key_cache2 = create_cache(self.backend_name, LOCATION=self.dirname, KEY_FUNCTION='cache.tests.custom_key_func') | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         self.cache.clear() |         self.cache.clear() | ||||||
| @@ -1097,7 +1098,7 @@ class FileBasedCacheTests(unittest.TestCase, BaseCacheTests): | |||||||
|  |  | ||||||
|     def test_zero_cull(self): |     def test_zero_cull(self): | ||||||
|         # Regression test for #15806 |         # Regression test for #15806 | ||||||
|         self.cache = get_cache(self.backend_name, LOCATION=self.dirname, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) |         self.cache = create_cache(self.backend_name, LOCATION=self.dirname, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0}) | ||||||
|         self.perform_cull_test(50, 19) |         self.perform_cull_test(50, 19) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1109,7 +1110,7 @@ class CustomCacheKeyValidationTests(unittest.TestCase): | |||||||
|  |  | ||||||
|     """ |     """ | ||||||
|     def test_custom_key_validation(self): |     def test_custom_key_validation(self): | ||||||
|         cache = get_cache('cache.liberal_backend.CacheClass') |         cache = create_cache('cache.liberal_backend.CacheClass') | ||||||
|  |  | ||||||
|         # this key is both longer than 250 characters, and has spaces |         # this key is both longer than 250 characters, and has spaces | ||||||
|         key = 'some key with spaces' * 15 |         key = 'some key with spaces' * 15 | ||||||
| @@ -1121,18 +1122,23 @@ class CustomCacheKeyValidationTests(unittest.TestCase): | |||||||
| class GetCacheTests(unittest.TestCase): | class GetCacheTests(unittest.TestCase): | ||||||
|  |  | ||||||
|     def test_simple(self): |     def test_simple(self): | ||||||
|         from django.core.cache import cache |         from django.core.cache import caches, DEFAULT_CACHE_ALIAS | ||||||
|         self.assertIsInstance(cache, get_cache('default').__class__) |         self.assertIsInstance( | ||||||
|  |             caches[DEFAULT_CACHE_ALIAS], | ||||||
|  |             create_cache('default').__class__ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         cache = get_cache( |         cache = create_cache( | ||||||
|             'django.core.cache.backends.dummy.DummyCache', **{'TIMEOUT': 120}) |             'django.core.cache.backends.dummy.DummyCache', | ||||||
|  |             **{'TIMEOUT': 120} | ||||||
|  |         ) | ||||||
|         self.assertEqual(cache.default_timeout, 120) |         self.assertEqual(cache.default_timeout, 120) | ||||||
|  |  | ||||||
|         self.assertRaises(InvalidCacheBackendError, get_cache, 'does_not_exist') |         self.assertRaises(InvalidCacheBackendError, create_cache, 'does_not_exist') | ||||||
|  |  | ||||||
|     def test_close(self): |     def test_close(self): | ||||||
|         from django.core import signals |         from django.core import signals | ||||||
|         cache = get_cache('cache.closeable_cache.CacheClass') |         cache = create_cache('cache.closeable_cache.CacheClass') | ||||||
|         self.assertFalse(cache.closed) |         self.assertFalse(cache.closed) | ||||||
|         signals.request_finished.send(self.__class__) |         signals.request_finished.send(self.__class__) | ||||||
|         self.assertTrue(cache.closed) |         self.assertTrue(cache.closed) | ||||||
| @@ -1153,7 +1159,7 @@ class CacheUtils(TestCase): | |||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.path = '/cache/test/' |         self.path = '/cache/test/' | ||||||
|         self.cache = get_cache('default') |         self.cache = caches['default'] | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
| @@ -1261,7 +1267,7 @@ class CacheHEADTest(TestCase): | |||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.path = '/cache/test/' |         self.path = '/cache/test/' | ||||||
|         self.cache = get_cache('default') |         self.cache = caches['default'] | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
| @@ -1314,7 +1320,7 @@ class CacheI18nTest(TestCase): | |||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.path = '/cache/test/' |         self.path = '/cache/test/' | ||||||
|         self.cache = get_cache('default') |         self.cache = create_cache('default') | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
| @@ -1581,8 +1587,8 @@ class CacheMiddlewareTest(IgnoreDeprecationWarningsMixin, TestCase): | |||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(CacheMiddlewareTest, self).setUp() |         super(CacheMiddlewareTest, self).setUp() | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|         self.default_cache = get_cache('default') |         self.default_cache = create_cache('default') | ||||||
|         self.other_cache = get_cache('other') |         self.other_cache = create_cache('other') | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         self.default_cache.clear() |         self.default_cache.clear() | ||||||
| @@ -1608,7 +1614,7 @@ class CacheMiddlewareTest(IgnoreDeprecationWarningsMixin, TestCase): | |||||||
|         # First, test with "defaults": |         # First, test with "defaults": | ||||||
|         as_view_decorator = CacheMiddleware(cache_alias=None, key_prefix=None) |         as_view_decorator = CacheMiddleware(cache_alias=None, key_prefix=None) | ||||||
|  |  | ||||||
|         self.assertEqual(as_view_decorator.cache_timeout, 300)  # Timeout value for 'default' cache, i.e. 300 |         self.assertEqual(as_view_decorator.cache_timeout, 30)  # Timeout value for 'default' cache, i.e. 30 | ||||||
|         self.assertEqual(as_view_decorator.key_prefix, '') |         self.assertEqual(as_view_decorator.key_prefix, '') | ||||||
|         self.assertEqual(as_view_decorator.cache_alias, 'default')  # Value of DEFAULT_CACHE_ALIAS from django.core.cache |         self.assertEqual(as_view_decorator.cache_alias, 'default')  # Value of DEFAULT_CACHE_ALIAS from django.core.cache | ||||||
|         self.assertEqual(as_view_decorator.cache_anonymous_only, False) |         self.assertEqual(as_view_decorator.cache_anonymous_only, False) | ||||||
| @@ -1755,7 +1761,7 @@ class CacheMiddlewareTest(IgnoreDeprecationWarningsMixin, TestCase): | |||||||
|         time.sleep(2) |         time.sleep(2) | ||||||
|  |  | ||||||
|         # ... the default cache will still hit |         # ... the default cache will still hit | ||||||
|         get_cache('default') |         caches['default'] | ||||||
|         response = default_view(request, '11') |         response = default_view(request, '11') | ||||||
|         self.assertEqual(response.content, b'Hello World 1') |         self.assertEqual(response.content, b'Hello World 1') | ||||||
|  |  | ||||||
| @@ -1801,7 +1807,7 @@ class TestWithTemplateResponse(TestCase): | |||||||
|     """ |     """ | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.path = '/cache/test/' |         self.path = '/cache/test/' | ||||||
|         self.cache = get_cache('default') |         self.cache = create_cache('default') | ||||||
|         self.factory = RequestFactory() |         self.factory = RequestFactory() | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
| @@ -1904,3 +1910,29 @@ class TestMakeTemplateFragmentKey(TestCase): | |||||||
|         key = make_template_fragment_key('spam', ['abc:def%']) |         key = make_template_fragment_key('spam', ['abc:def%']) | ||||||
|         self.assertEqual(key, |         self.assertEqual(key, | ||||||
|             'template.cache.spam.f27688177baec990cdf3fbd9d9c3f469') |             'template.cache.spam.f27688177baec990cdf3fbd9d9c3f469') | ||||||
|  |  | ||||||
|  | class CacheHandlerTest(TestCase): | ||||||
|  |     def test_same_instance(self): | ||||||
|  |         """ | ||||||
|  |         Attempting to retrieve the same alias should yield the same instance. | ||||||
|  |         """ | ||||||
|  |         cache1 = caches['default'] | ||||||
|  |         cache2 = caches['default'] | ||||||
|  |  | ||||||
|  |         self.assertTrue(cache1 is cache2) | ||||||
|  |  | ||||||
|  |     def test_per_thread(self): | ||||||
|  |         """ | ||||||
|  |         Requesting the same alias from separate threads should yield separate | ||||||
|  |         instances. | ||||||
|  |         """ | ||||||
|  |         c = [] | ||||||
|  |         def runner(): | ||||||
|  |             c.append(caches['default']) | ||||||
|  |  | ||||||
|  |         for x in range(2): | ||||||
|  |             t = threading.Thread(target=runner) | ||||||
|  |             t.start() | ||||||
|  |             t.join() | ||||||
|  |  | ||||||
|  |         self.assertFalse(c[0] is c[1]) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user