Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #21146 - DatabaseCache converts expires to python value

DatabaseCache uses raw cursors to bypass the ORM. This prevents it from
being used by database backends that require special handling of datetime
values.

There is no easy way to test this, so no tests added.
  • Loading branch information...
commit d5606b57637f00c4349732d79541faa41acfe29c 1 parent 209de62
@manfre manfre authored akaariai committed
Showing with 18 additions and 3 deletions.
  1. +18 −3 django/core/cache/backends/db.py
View
21 django/core/cache/backends/db.py
@@ -11,6 +11,7 @@
from django.conf import settings
from django.core.cache.backends.base import BaseCache, DEFAULT_TIMEOUT
from django.db import connections, transaction, router, DatabaseError
+from django.db.backends.utils import typecast_timestamp
from django.utils import timezone, six
from django.utils.encoding import force_bytes
@@ -65,8 +66,13 @@ def get(self, key, default=None, version=None):
if row is None:
return default
now = timezone.now()
-
- if row[2] < now:
+ expires = row[2]
+ if connections[db].features.needs_datetime_string_cast and not isinstance(expires, datetime):
+ # Note: typecasting is needed by some 3rd party database backends.
+ # All core backends work without typecasting, so be careful about
+ # changes here - test suite will NOT pick regressions here.
+ expires = typecast_timestamp(str(expires))
+ if expires < now:
db = router.db_for_write(self.cache_model_class)
cursor = connections[db].cursor()
cursor.execute("DELETE FROM %s "
@@ -112,12 +118,21 @@ def _base_set(self, mode, key, value, timeout=DEFAULT_TIMEOUT):
if six.PY3:
b64encoded = b64encoded.decode('latin1')
try:
+ # Note: typecasting for datetimes is needed by some 3rd party
+ # database backends. All core backends work without typecasting,
+ # so be careful about changes here - test suite will NOT pick
+ # regressions.
with transaction.atomic(using=db):
cursor.execute("SELECT cache_key, expires FROM %s "
"WHERE cache_key = %%s" % table, [key])
result = cursor.fetchone()
+ if result:
+ current_expires = result[1]
+ if (connections[db].features.needs_datetime_string_cast and not
+ isinstance(current_expires, datetime)):
+ current_expires = typecast_timestamp(str(current_expires))
exp = connections[db].ops.value_to_db_datetime(exp)
- if result and (mode == 'set' or (mode == 'add' and result[1] < now)):
+ if result and (mode == 'set' or (mode == 'add' and current_expires < now)):
cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
"WHERE cache_key = %%s" % table,
[b64encoded, exp, key])
Please sign in to comment.
Something went wrong with that request. Please try again.