cache.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. from django.conf import settings
  2. from django.contrib.sessions.backends.base import CreateError, SessionBase, UpdateError
  3. from django.core.cache import caches
  4. KEY_PREFIX = "django.contrib.sessions.cache"
  5. class SessionStore(SessionBase):
  6. """
  7. A cache-based session store.
  8. """
  9. cache_key_prefix = KEY_PREFIX
  10. def __init__(self, session_key=None):
  11. self._cache = caches[settings.SESSION_CACHE_ALIAS]
  12. super().__init__(session_key)
  13. @property
  14. def cache_key(self):
  15. return self.cache_key_prefix + self._get_or_create_session_key()
  16. def load(self):
  17. try:
  18. session_data = self._cache.get(self.cache_key)
  19. except Exception:
  20. # Some backends (e.g. memcache) raise an exception on invalid
  21. # cache keys. If this happens, reset the session. See #17810.
  22. session_data = None
  23. if session_data is not None:
  24. return session_data
  25. self._session_key = None
  26. return {}
  27. def create(self):
  28. # Because a cache can fail silently (e.g. memcache), we don't know if
  29. # we are failing to create a new session because of a key collision or
  30. # because the cache is missing. So we try for a (large) number of times
  31. # and then raise an exception. That's the risk you shoulder if using
  32. # cache backing.
  33. for i in range(10000):
  34. self._session_key = self._get_new_session_key()
  35. try:
  36. self.save(must_create=True)
  37. except CreateError:
  38. continue
  39. self.modified = True
  40. return
  41. raise RuntimeError(
  42. "Unable to create a new session key. "
  43. "It is likely that the cache is unavailable."
  44. )
  45. def save(self, must_create=False):
  46. if self.session_key is None:
  47. return self.create()
  48. if must_create:
  49. func = self._cache.add
  50. elif self._cache.get(self.cache_key) is not None:
  51. func = self._cache.set
  52. else:
  53. raise UpdateError
  54. result = func(
  55. self.cache_key,
  56. self._get_session(no_load=must_create),
  57. self.get_expiry_age(),
  58. )
  59. if must_create and not result:
  60. raise CreateError
  61. def exists(self, session_key):
  62. return (
  63. bool(session_key) and (self.cache_key_prefix + session_key) in self._cache
  64. )
  65. def delete(self, session_key=None):
  66. if session_key is None:
  67. if self.session_key is None:
  68. return
  69. session_key = self.session_key
  70. self._cache.delete(self.cache_key_prefix + session_key)
  71. @classmethod
  72. def clear_expired(cls):
  73. pass