cached_db.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. """
  2. Cached, database-backed sessions.
  3. """
  4. import logging
  5. from django.conf import settings
  6. from django.contrib.sessions.backends.db import SessionStore as DBStore
  7. from django.core.cache import caches
  8. KEY_PREFIX = "django.contrib.sessions.cached_db"
  9. logger = logging.getLogger("django.contrib.sessions")
  10. class SessionStore(DBStore):
  11. """
  12. Implement cached, database backed sessions.
  13. """
  14. cache_key_prefix = KEY_PREFIX
  15. def __init__(self, session_key=None):
  16. self._cache = caches[settings.SESSION_CACHE_ALIAS]
  17. super().__init__(session_key)
  18. @property
  19. def cache_key(self):
  20. return self.cache_key_prefix + self._get_or_create_session_key()
  21. async def acache_key(self):
  22. return self.cache_key_prefix + await self._aget_or_create_session_key()
  23. def load(self):
  24. try:
  25. data = self._cache.get(self.cache_key)
  26. except Exception:
  27. # Some backends (e.g. memcache) raise an exception on invalid
  28. # cache keys. If this happens, reset the session. See #17810.
  29. data = None
  30. if data is None:
  31. s = self._get_session_from_db()
  32. if s:
  33. data = self.decode(s.session_data)
  34. self._cache.set(
  35. self.cache_key, data, self.get_expiry_age(expiry=s.expire_date)
  36. )
  37. else:
  38. data = {}
  39. return data
  40. async def aload(self):
  41. try:
  42. data = await self._cache.aget(await self.acache_key())
  43. except Exception:
  44. # Some backends (e.g. memcache) raise an exception on invalid
  45. # cache keys. If this happens, reset the session. See #17810.
  46. data = None
  47. if data is None:
  48. s = await self._aget_session_from_db()
  49. if s:
  50. data = self.decode(s.session_data)
  51. await self._cache.aset(
  52. await self.acache_key(),
  53. data,
  54. await self.aget_expiry_age(expiry=s.expire_date),
  55. )
  56. else:
  57. data = {}
  58. return data
  59. def exists(self, session_key):
  60. return (
  61. session_key
  62. and (self.cache_key_prefix + session_key) in self._cache
  63. or super().exists(session_key)
  64. )
  65. async def aexists(self, session_key):
  66. return (
  67. session_key
  68. and (self.cache_key_prefix + session_key) in self._cache
  69. or await super().aexists(session_key)
  70. )
  71. def save(self, must_create=False):
  72. super().save(must_create)
  73. try:
  74. self._cache.set(self.cache_key, self._session, self.get_expiry_age())
  75. except Exception:
  76. logger.exception("Error saving to cache (%s)", self._cache)
  77. async def asave(self, must_create=False):
  78. await super().asave(must_create)
  79. try:
  80. await self._cache.aset(
  81. await self.acache_key(),
  82. self._session,
  83. await self.aget_expiry_age(),
  84. )
  85. except Exception:
  86. logger.exception("Error saving to cache (%s)", self._cache)
  87. def delete(self, session_key=None):
  88. super().delete(session_key)
  89. if session_key is None:
  90. if self.session_key is None:
  91. return
  92. session_key = self.session_key
  93. self._cache.delete(self.cache_key_prefix + session_key)
  94. async def adelete(self, session_key=None):
  95. await super().adelete(session_key)
  96. if session_key is None:
  97. if self.session_key is None:
  98. return
  99. session_key = self.session_key
  100. await self._cache.adelete(self.cache_key_prefix + session_key)
  101. def flush(self):
  102. """
  103. Remove the current session data from the database and regenerate the
  104. key.
  105. """
  106. self.clear()
  107. self.delete(self.session_key)
  108. self._session_key = None
  109. async def aflush(self):
  110. """See flush()."""
  111. self.clear()
  112. await self.adelete(self.session_key)
  113. self._session_key = None