mirror of
				https://github.com/django/django.git
				synced 2025-11-04 13:39:16 +00:00 
			
		
		
		
	Fixed #21012 -- Thread-local caches, like databases.
This commit is contained in:
		
							parent
							
								
									3ca0815c0b
								
							
						
					
					
						commit
						ee7eb0f73e
					
				
					 14 changed files with 303 additions and 143 deletions
				
			
		| 
						 | 
					@ -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])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue