PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/django/core/cache/__init__.py

https://github.com/Tippr/django
Python | 187 lines | 178 code | 0 blank | 9 comment | 2 complexity | ed9e46ecb48a3e03c603d644aa2c1e22 MD5 | raw file
  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 not access a cache backend directly; instead it should
  8. either use the "cache" variable made available here, or it should use the
  9. get_cache() function made available here. get_cache() takes a backend URI
  10. (e.g. "memcached://127.0.0.1:11211/") and returns an instance of a backend
  11. cache class.
  12. See docs/topics/cache.txt for information on the public API.
  13. """
  14. from django.conf import settings
  15. from django.core import signals
  16. from django.core.cache.backends.base import (
  17. InvalidCacheBackendError, CacheKeyWarning, BaseCache)
  18. from django.core.exceptions import ImproperlyConfigured
  19. from django.utils import importlib
  20. try:
  21. # The mod_python version is more efficient, so try importing it first.
  22. from mod_python.util import parse_qsl
  23. except ImportError:
  24. try:
  25. # Python 2.6 and greater
  26. from urlparse import parse_qsl
  27. except ImportError:
  28. # Python 2.5. Works on Python 2.6 but raises PendingDeprecationWarning
  29. from cgi import parse_qsl
  30. __all__ = [
  31. 'get_cache', 'cache', 'DEFAULT_CACHE_ALIAS'
  32. ]
  33. # Name for use in settings file --> name of module in "backends" directory.
  34. # Any backend scheme that is not in this dictionary is treated as a Python
  35. # import path to a custom backend.
  36. BACKENDS = {
  37. 'memcached': 'memcached',
  38. 'locmem': 'locmem',
  39. 'file': 'filebased',
  40. 'db': 'db',
  41. 'dummy': 'dummy',
  42. }
  43. DEFAULT_CACHE_ALIAS = 'default'
  44. def parse_backend_uri(backend_uri):
  45. """
  46. Converts the "backend_uri" into a cache scheme ('db', 'memcached', etc), a
  47. host and any extra params that are required for the backend. Returns a
  48. (scheme, host, params) tuple.
  49. """
  50. if backend_uri.find(':') == -1:
  51. raise InvalidCacheBackendError("Backend URI must start with scheme://")
  52. scheme, rest = backend_uri.split(':', 1)
  53. if not rest.startswith('//'):
  54. raise InvalidCacheBackendError("Backend URI must start with scheme://")
  55. host = rest[2:]
  56. qpos = rest.find('?')
  57. if qpos != -1:
  58. params = dict(parse_qsl(rest[qpos+1:]))
  59. host = rest[2:qpos]
  60. else:
  61. params = {}
  62. if host.endswith('/'):
  63. host = host[:-1]
  64. return scheme, host, params
  65. if not settings.CACHES:
  66. legacy_backend = getattr(settings, 'CACHE_BACKEND', None)
  67. if legacy_backend:
  68. import warnings
  69. warnings.warn(
  70. "settings.CACHE_* is deprecated; use settings.CACHES instead.",
  71. DeprecationWarning
  72. )
  73. else:
  74. # The default cache setting is put here so that we
  75. # can differentiate between a user who has provided
  76. # an explicit CACHE_BACKEND of locmem://, and the
  77. # default value. When the deprecation cycle has completed,
  78. # the default can be restored to global_settings.py
  79. settings.CACHE_BACKEND = 'locmem://'
  80. # Mapping for new-style cache backend api
  81. backend_classes = {
  82. 'memcached': 'memcached.CacheClass',
  83. 'locmem': 'locmem.LocMemCache',
  84. 'file': 'filebased.FileBasedCache',
  85. 'db': 'db.DatabaseCache',
  86. 'dummy': 'dummy.DummyCache',
  87. }
  88. engine, host, params = parse_backend_uri(settings.CACHE_BACKEND)
  89. if engine in backend_classes:
  90. engine = 'django.core.cache.backends.%s' % backend_classes[engine]
  91. else:
  92. engine = '%s.CacheClass' % engine
  93. defaults = {
  94. 'BACKEND': engine,
  95. 'LOCATION': host,
  96. }
  97. defaults.update(params)
  98. settings.CACHES[DEFAULT_CACHE_ALIAS] = defaults
  99. if DEFAULT_CACHE_ALIAS not in settings.CACHES:
  100. raise ImproperlyConfigured("You must define a '%s' cache" % DEFAULT_CACHE_ALIAS)
  101. def parse_backend_conf(backend, **kwargs):
  102. """
  103. Helper function to parse the backend configuration
  104. that doesn't use the URI notation.
  105. """
  106. # Try to get the CACHES entry for the given backend name first
  107. conf = settings.CACHES.get(backend, None)
  108. if conf is not None:
  109. args = conf.copy()
  110. args.update(kwargs)
  111. backend = args.pop('BACKEND')
  112. location = args.pop('LOCATION', '')
  113. return backend, location, args
  114. else:
  115. try:
  116. # Trying to import the given backend, in case it's a dotted path
  117. mod_path, cls_name = backend.rsplit('.', 1)
  118. mod = importlib.import_module(mod_path)
  119. backend_cls = getattr(mod, cls_name)
  120. except (AttributeError, ImportError, ValueError):
  121. raise InvalidCacheBackendError("Could not find backend '%s'" % backend)
  122. location = kwargs.pop('LOCATION', '')
  123. return backend, location, kwargs
  124. raise InvalidCacheBackendError(
  125. "Couldn't find a cache backend named '%s'" % backend)
  126. def get_cache(backend, **kwargs):
  127. """
  128. Function to load a cache backend dynamically. This is flexible by design
  129. to allow different use cases:
  130. To load a backend with the old URI-based notation::
  131. cache = get_cache('locmem://')
  132. To load a backend that is pre-defined in the settings::
  133. cache = get_cache('default')
  134. To load a backend with its dotted import path,
  135. including arbitrary options::
  136. cache = get_cache('django.core.cache.backends.memcached.MemcachedCache', **{
  137. 'LOCATION': '127.0.0.1:11211', 'TIMEOUT': 30,
  138. })
  139. """
  140. try:
  141. if '://' in backend:
  142. # for backwards compatibility
  143. backend, location, params = parse_backend_uri(backend)
  144. if backend in BACKENDS:
  145. backend = 'django.core.cache.backends.%s' % BACKENDS[backend]
  146. params.update(kwargs)
  147. mod = importlib.import_module(backend)
  148. backend_cls = mod.CacheClass
  149. else:
  150. backend, location, params = parse_backend_conf(backend, **kwargs)
  151. mod_path, cls_name = backend.rsplit('.', 1)
  152. mod = importlib.import_module(mod_path)
  153. backend_cls = getattr(mod, cls_name)
  154. except (AttributeError, ImportError), e:
  155. raise InvalidCacheBackendError(
  156. "Could not find backend '%s': %s" % (backend, e))
  157. return backend_cls(location, params)
  158. cache = get_cache(DEFAULT_CACHE_ALIAS)
  159. # Some caches -- python-memcached in particular -- need to do a cleanup at the
  160. # end of a request cycle. If the cache provides a close() method, wire it up
  161. # here.
  162. if hasattr(cache, 'close'):
  163. signals.request_finished.connect(cache.close)