You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

__init__.py 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. """
  2. Caching framework.
  3. This package defines set of cache backends that all conform to a simple API.
  4. In a nutshell, a cache is a set of values -- which can be any object that
  5. may be pickled -- identified by string keys. For the complete API, see
  6. the abstract BaseCache class in django.core.cache.backends.base.
  7. Client code should use the `cache` variable defined here to access the default
  8. cache backend and look up non-default cache backends in the `caches` dict-like
  9. object.
  10. See docs/topics/cache.txt for information on the public API.
  11. """
  12. from threading import local
  13. from django.conf import settings
  14. from django.core import signals
  15. from django.core.cache.backends.base import (
  16. BaseCache, CacheKeyWarning, InvalidCacheBackendError,
  17. )
  18. from django.utils.module_loading import import_string
  19. __all__ = [
  20. 'cache', 'caches', 'DEFAULT_CACHE_ALIAS', 'InvalidCacheBackendError',
  21. 'CacheKeyWarning', 'BaseCache',
  22. ]
  23. DEFAULT_CACHE_ALIAS = 'default'
  24. def _create_cache(backend, **kwargs):
  25. try:
  26. # Try to get the CACHES entry for the given backend name first
  27. try:
  28. conf = settings.CACHES[backend]
  29. except KeyError:
  30. try:
  31. # Trying to import the given backend, in case it's a dotted path
  32. import_string(backend)
  33. except ImportError as e:
  34. raise InvalidCacheBackendError("Could not find backend '%s': %s" % (
  35. backend, e))
  36. location = kwargs.pop('LOCATION', '')
  37. params = kwargs
  38. else:
  39. params = {**conf, **kwargs}
  40. backend = params.pop('BACKEND')
  41. location = params.pop('LOCATION', '')
  42. backend_cls = import_string(backend)
  43. except ImportError as e:
  44. raise InvalidCacheBackendError(
  45. "Could not find backend '%s': %s" % (backend, e))
  46. return backend_cls(location, params)
  47. class CacheHandler:
  48. """
  49. A Cache Handler to manage access to Cache instances.
  50. Ensure only one instance of each alias exists per thread.
  51. """
  52. def __init__(self):
  53. self._caches = local()
  54. def __getitem__(self, alias):
  55. try:
  56. return self._caches.caches[alias]
  57. except AttributeError:
  58. self._caches.caches = {}
  59. except KeyError:
  60. pass
  61. if alias not in settings.CACHES:
  62. raise InvalidCacheBackendError(
  63. "Could not find config for '%s' in settings.CACHES" % alias
  64. )
  65. cache = _create_cache(alias)
  66. self._caches.caches[alias] = cache
  67. return cache
  68. def all(self):
  69. return getattr(self._caches, 'caches', {}).values()
  70. caches = CacheHandler()
  71. class DefaultCacheProxy:
  72. """
  73. Proxy access to the default Cache object's attributes.
  74. This allows the legacy `cache` object to be thread-safe using the new
  75. ``caches`` API.
  76. """
  77. def __getattr__(self, name):
  78. return getattr(caches[DEFAULT_CACHE_ALIAS], name)
  79. def __setattr__(self, name, value):
  80. return setattr(caches[DEFAULT_CACHE_ALIAS], name, value)
  81. def __delattr__(self, name):
  82. return delattr(caches[DEFAULT_CACHE_ALIAS], name)
  83. def __contains__(self, key):
  84. return key in caches[DEFAULT_CACHE_ALIAS]
  85. def __eq__(self, other):
  86. return caches[DEFAULT_CACHE_ALIAS] == other
  87. cache = DefaultCacheProxy()
  88. def close_caches(**kwargs):
  89. # Some caches -- python-memcached in particular -- need to do a cleanup at the
  90. # end of a request cycle. If not implemented in a particular backend
  91. # cache.close is a no-op
  92. for cache in caches.all():
  93. cache.close()
  94. signals.request_finished.connect(close_caches)