Skip to content
/ django Public

Commit 6fe22b3

Browse files
zedrbmispelon
authored andcommitted
Fixed #22085 -- Added a feature for setting non-expiring keys as the default.
This feature allows the default `TIMEOUT` Cache argument to be set to `None`, so that cache instances can set a non-expiring key as the default, instead of using the default value of 5 minutes. Previously, this was possible only by passing `None` as an argument to the set() method of objects of type `BaseCache` (and subtypes).
1 parent 24f0113 commit 6fe22b3

File tree

5 files changed

+101
-8
lines changed

5 files changed

+101
-8
lines changed

django/core/cache/backends/base.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ def get_key_func(key_func):
5252
class BaseCache(object):
5353
def __init__(self, params):
5454
timeout = params.get('timeout', params.get('TIMEOUT', 300))
55-
try:
56-
timeout = int(timeout)
57-
except (ValueError, TypeError):
58-
timeout = 300
55+
if timeout is not None:
56+
try:
57+
timeout = int(timeout)
58+
except (ValueError, TypeError):
59+
timeout = 300
5960
self.default_timeout = timeout
6061

6162
options = params.get('OPTIONS', {})

docs/ref/settings.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ Default: 300
255255

256256
The number of seconds before a cache entry is considered stale.
257257

258+
.. versionadded:: 1.7
259+
260+
If the value of this settings is ``None``, cache entries will not expire.
261+
258262
.. setting:: CACHES-VERSION
259263

260264
VERSION

docs/releases/1.7.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,11 @@ Cache
441441
thread-safe any more, as :data:`django.core.cache.caches` now yields
442442
different instances per thread.
443443

444+
* Defining the :setting:`TIMEOUT <CACHES-TIMEOUT>` argument of the
445+
:setting:`CACHES` setting as ``None`` will set the cache keys as
446+
"non-expiring" by default. Previously, it was only possible to pass
447+
``timeout=None` to the cache backend's ``set()`` method.
448+
444449
Email
445450
^^^^^
446451

docs/topics/cache.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,14 @@ Each cache backend can be given additional arguments to control caching
363363
behavior. These arguments are provided as additional keys in the
364364
:setting:`CACHES` setting. Valid arguments are as follows:
365365

366+
366367
* :setting:`TIMEOUT <CACHES-TIMEOUT>`: The default timeout, in
367-
seconds, to use for the cache. This argument defaults to ``300``
368-
seconds (5 minutes).
368+
seconds, to use for the cache. This argument defaults to ``300`` seconds (5 minutes).
369+
370+
.. versionadded:: 1.7
371+
372+
You can set ``TIMEOUT`` to ``None`` so that, by default, cache keys never
373+
expire.
369374

370375
* :setting:`OPTIONS <CACHES-OPTIONS>`: Any options that should be
371376
passed to the cache backend. The list of valid options will vary

tests/cache/tests.py

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import os
88
import re
9+
import copy
910
import shutil
1011
import tempfile
1112
import threading
@@ -15,7 +16,8 @@
1516

1617
from django.conf import settings
1718
from django.core import management
18-
from django.core.cache import cache, caches, CacheKeyWarning, InvalidCacheBackendError
19+
from django.core.cache import (cache, caches, CacheKeyWarning,
20+
InvalidCacheBackendError, DEFAULT_CACHE_ALIAS)
1921
from django.db import connection, router, transaction
2022
from django.core.cache.utils import make_template_fragment_key
2123
from django.http import HttpResponse, StreamingHttpResponse
@@ -1175,7 +1177,7 @@ def test_custom_key_validation(self):
11751177
class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase):
11761178

11771179
def test_simple(self):
1178-
from django.core.cache import caches, DEFAULT_CACHE_ALIAS, get_cache
1180+
from django.core.cache import caches, get_cache
11791181
self.assertIsInstance(
11801182
caches[DEFAULT_CACHE_ALIAS],
11811183
get_cache('default').__class__
@@ -1204,6 +1206,82 @@ def test_close_deprecated(self):
12041206
self.assertTrue(cache.closed)
12051207

12061208

1209+
DEFAULT_MEMORY_CACHES_SETTINGS = {
1210+
'default': {
1211+
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1212+
'LOCATION': 'unique-snowflake',
1213+
}
1214+
}
1215+
NEVER_EXPIRING_CACHES_SETTINGS = copy.deepcopy(DEFAULT_MEMORY_CACHES_SETTINGS)
1216+
NEVER_EXPIRING_CACHES_SETTINGS['default']['TIMEOUT'] = None
1217+
1218+
1219+
class DefaultNonExpiringCacheKeyTests(TestCase):
1220+
"""Tests that verify that settings having Cache arguments with a TIMEOUT
1221+
set to `None` will create Caches that will set non-expiring keys.
1222+
1223+
This fixes ticket #22085.
1224+
"""
1225+
def setUp(self):
1226+
# The 5 minute (300 seconds) default expiration time for keys is
1227+
# defined in the implementation of the initializer method of the
1228+
# BaseCache type.
1229+
self.DEFAULT_TIMEOUT = caches[DEFAULT_CACHE_ALIAS].default_timeout
1230+
1231+
def tearDown(self):
1232+
del(self.DEFAULT_TIMEOUT)
1233+
1234+
def test_default_expiration_time_for_keys_is_5_minutes(self):
1235+
"""The default expiration time of a cache key is 5 minutes.
1236+
1237+
This value is defined inside the __init__() method of the
1238+
:class:`django.core.cache.backends.base.BaseCache` type.
1239+
"""
1240+
self.assertEquals(300, self.DEFAULT_TIMEOUT)
1241+
1242+
def test_caches_with_unset_timeout_has_correct_default_timeout(self):
1243+
"""Caches that have the TIMEOUT parameter undefined in the default
1244+
settings will use the default 5 minute timeout.
1245+
"""
1246+
cache = caches[DEFAULT_CACHE_ALIAS]
1247+
self.assertEquals(self.DEFAULT_TIMEOUT, cache.default_timeout)
1248+
1249+
@override_settings(CACHES=NEVER_EXPIRING_CACHES_SETTINGS)
1250+
def test_caches_set_with_timeout_as_none_has_correct_default_timeout(self):
1251+
"""Memory caches that have the TIMEOUT parameter set to `None` in the
1252+
default settings with have `None` as the default timeout.
1253+
1254+
This means "no timeout".
1255+
"""
1256+
cache = caches[DEFAULT_CACHE_ALIAS]
1257+
self.assertIs(None, cache.default_timeout)
1258+
self.assertEquals(None, cache.get_backend_timeout())
1259+
1260+
@override_settings(CACHES=DEFAULT_MEMORY_CACHES_SETTINGS)
1261+
def test_caches_with_unset_timeout_set_expiring_key(self):
1262+
"""Memory caches that have the TIMEOUT parameter unset will set cache
1263+
keys having the default 5 minute timeout.
1264+
"""
1265+
key = "my-key"
1266+
value = "my-value"
1267+
cache = caches[DEFAULT_CACHE_ALIAS]
1268+
cache.set(key, value)
1269+
cache_key = cache.make_key(key)
1270+
self.assertNotEquals(None, cache._expire_info[cache_key])
1271+
1272+
@override_settings(CACHES=NEVER_EXPIRING_CACHES_SETTINGS)
1273+
def text_caches_set_with_timeout_as_none_set_non_expiring_key(self):
1274+
"""Memory caches that have the TIMEOUT parameter set to `None` will set
1275+
a non expiring key by default.
1276+
"""
1277+
key = "another-key"
1278+
value = "another-value"
1279+
cache = caches[DEFAULT_CACHE_ALIAS]
1280+
cache.set(key, value)
1281+
cache_key = cache.make_key(key)
1282+
self.assertEquals(None, cache._expire_info[cache_key])
1283+
1284+
12071285
@override_settings(
12081286
CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix',
12091287
CACHE_MIDDLEWARE_SECONDS=1,

0 commit comments

Comments
 (0)