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).
This commit is contained in:
zedr 2014-02-23 22:58:26 +00:00 committed by Baptiste Mispelon
parent 24f0113fb9
commit 6fe22b30e0
5 changed files with 101 additions and 8 deletions

View File

@ -52,6 +52,7 @@ def get_key_func(key_func):
class BaseCache(object): class BaseCache(object):
def __init__(self, params): def __init__(self, params):
timeout = params.get('timeout', params.get('TIMEOUT', 300)) timeout = params.get('timeout', params.get('TIMEOUT', 300))
if timeout is not None:
try: try:
timeout = int(timeout) timeout = int(timeout)
except (ValueError, TypeError): except (ValueError, TypeError):

View File

@ -255,6 +255,10 @@ Default: 300
The number of seconds before a cache entry is considered stale. The number of seconds before a cache entry is considered stale.
.. versionadded:: 1.7
If the value of this settings is ``None``, cache entries will not expire.
.. setting:: CACHES-VERSION .. setting:: CACHES-VERSION
VERSION VERSION

View File

@ -441,6 +441,11 @@ Cache
thread-safe any more, as :data:`django.core.cache.caches` now yields thread-safe any more, as :data:`django.core.cache.caches` now yields
different instances per thread. different instances per thread.
* Defining the :setting:`TIMEOUT <CACHES-TIMEOUT>` argument of the
:setting:`CACHES` setting as ``None`` will set the cache keys as
"non-expiring" by default. Previously, it was only possible to pass
``timeout=None` to the cache backend's ``set()`` method.
Email Email
^^^^^ ^^^^^

View File

@ -363,9 +363,14 @@ Each cache backend can be given additional arguments to control caching
behavior. These arguments are provided as additional keys in the behavior. These arguments are provided as additional keys in the
:setting:`CACHES` setting. Valid arguments are as follows: :setting:`CACHES` setting. Valid arguments are as follows:
* :setting:`TIMEOUT <CACHES-TIMEOUT>`: The default timeout, in * :setting:`TIMEOUT <CACHES-TIMEOUT>`: The default timeout, in
seconds, to use for the cache. This argument defaults to ``300`` seconds, to use for the cache. This argument defaults to ``300`` seconds (5 minutes).
seconds (5 minutes).
.. versionadded:: 1.7
You can set ``TIMEOUT`` to ``None`` so that, by default, cache keys never
expire.
* :setting:`OPTIONS <CACHES-OPTIONS>`: Any options that should be * :setting:`OPTIONS <CACHES-OPTIONS>`: Any options that should be
passed to the cache backend. The list of valid options will vary passed to the cache backend. The list of valid options will vary

82
tests/cache/tests.py vendored
View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import os import os
import re import re
import copy
import shutil import shutil
import tempfile import tempfile
import threading import threading
@ -15,7 +16,8 @@ import warnings
from django.conf import settings from django.conf import settings
from django.core import management from django.core import management
from django.core.cache import cache, caches, CacheKeyWarning, InvalidCacheBackendError from django.core.cache import (cache, caches, CacheKeyWarning,
InvalidCacheBackendError, DEFAULT_CACHE_ALIAS)
from django.db import connection, router, transaction from django.db import connection, router, transaction
from django.core.cache.utils import make_template_fragment_key from django.core.cache.utils import make_template_fragment_key
from django.http import HttpResponse, StreamingHttpResponse from django.http import HttpResponse, StreamingHttpResponse
@ -1175,7 +1177,7 @@ class CustomCacheKeyValidationTests(TestCase):
class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase): class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase):
def test_simple(self): def test_simple(self):
from django.core.cache import caches, DEFAULT_CACHE_ALIAS, get_cache from django.core.cache import caches, get_cache
self.assertIsInstance( self.assertIsInstance(
caches[DEFAULT_CACHE_ALIAS], caches[DEFAULT_CACHE_ALIAS],
get_cache('default').__class__ get_cache('default').__class__
@ -1204,6 +1206,82 @@ class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase):
self.assertTrue(cache.closed) self.assertTrue(cache.closed)
DEFAULT_MEMORY_CACHES_SETTINGS = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
NEVER_EXPIRING_CACHES_SETTINGS = copy.deepcopy(DEFAULT_MEMORY_CACHES_SETTINGS)
NEVER_EXPIRING_CACHES_SETTINGS['default']['TIMEOUT'] = None
class DefaultNonExpiringCacheKeyTests(TestCase):
"""Tests that verify that settings having Cache arguments with a TIMEOUT
set to `None` will create Caches that will set non-expiring keys.
This fixes ticket #22085.
"""
def setUp(self):
# The 5 minute (300 seconds) default expiration time for keys is
# defined in the implementation of the initializer method of the
# BaseCache type.
self.DEFAULT_TIMEOUT = caches[DEFAULT_CACHE_ALIAS].default_timeout
def tearDown(self):
del(self.DEFAULT_TIMEOUT)
def test_default_expiration_time_for_keys_is_5_minutes(self):
"""The default expiration time of a cache key is 5 minutes.
This value is defined inside the __init__() method of the
:class:`django.core.cache.backends.base.BaseCache` type.
"""
self.assertEquals(300, self.DEFAULT_TIMEOUT)
def test_caches_with_unset_timeout_has_correct_default_timeout(self):
"""Caches that have the TIMEOUT parameter undefined in the default
settings will use the default 5 minute timeout.
"""
cache = caches[DEFAULT_CACHE_ALIAS]
self.assertEquals(self.DEFAULT_TIMEOUT, cache.default_timeout)
@override_settings(CACHES=NEVER_EXPIRING_CACHES_SETTINGS)
def test_caches_set_with_timeout_as_none_has_correct_default_timeout(self):
"""Memory caches that have the TIMEOUT parameter set to `None` in the
default settings with have `None` as the default timeout.
This means "no timeout".
"""
cache = caches[DEFAULT_CACHE_ALIAS]
self.assertIs(None, cache.default_timeout)
self.assertEquals(None, cache.get_backend_timeout())
@override_settings(CACHES=DEFAULT_MEMORY_CACHES_SETTINGS)
def test_caches_with_unset_timeout_set_expiring_key(self):
"""Memory caches that have the TIMEOUT parameter unset will set cache
keys having the default 5 minute timeout.
"""
key = "my-key"
value = "my-value"
cache = caches[DEFAULT_CACHE_ALIAS]
cache.set(key, value)
cache_key = cache.make_key(key)
self.assertNotEquals(None, cache._expire_info[cache_key])
@override_settings(CACHES=NEVER_EXPIRING_CACHES_SETTINGS)
def text_caches_set_with_timeout_as_none_set_non_expiring_key(self):
"""Memory caches that have the TIMEOUT parameter set to `None` will set
a non expiring key by default.
"""
key = "another-key"
value = "another-value"
cache = caches[DEFAULT_CACHE_ALIAS]
cache.set(key, value)
cache_key = cache.make_key(key)
self.assertEquals(None, cache._expire_info[cache_key])
@override_settings( @override_settings(
CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix', CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix',
CACHE_MIDDLEWARE_SECONDS=1, CACHE_MIDDLEWARE_SECONDS=1,