PageRenderTime 56ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/django/core/cache/__init__.py

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