Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixes #21012 -- New cache API to avoid connection exhaustion. #1539

Closed
wants to merge 2 commits into from

2 participants

@funkybob

Provide a dict of caches to avoid creating multiple instances of the caches configured in CACHES.

Still needs tests and some more docs.

docs/topics/cache.txt
((15 lines not shown))
-The cache module, ``django.core.cache``, has a ``cache`` object that's
-automatically created from the ``'default'`` entry in the :setting:`CACHES`
-setting::
+The `default` cache is available as ``django.core.cache.cache`` for backward
@loic Collaborator
loic added a note

[...]cache is still available[...]

Also `` (double backticks) around default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
docs/topics/cache.txt
@@ -679,22 +679,32 @@ pickling.)
Accessing the cache
-------------------
-.. function:: django.core.cache.get_cache(backend, **kwargs)
+.. versionchanged:: 1.7
+
+ The cache module, ``django.core.cache``, provides a dict-like object for
+ accessing the caches defined in :settings:`CACHES`. These are created on
@loic Collaborator
loic added a note

:setting: (singular).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/cache/liberal_backend.py
@@ -8,3 +8,10 @@ def validate_key(self, key):
class CacheClass(LiberalKeyValidationMixin, LocMemCache):
pass
+class CountingCache(LocMemCache):
+ """A Cache class that tracks how many times it has been instantiated."""
+ count = 0
+ def __init__(self, *args, **kwargs):
+ super(CountingCache, self).__init__(*args, **kwargs)
+ self.__class__.count += 1
+
@loic Collaborator
loic added a note

1 line too many.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@funkybob funkybob closed this
@funkybob funkybob deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 1, 2013
  1. @funkybob
  2. @funkybob

    Minor tweaks

    funkybob authored
This page is out of date. Refresh to see the latest.
View
11 django/core/cache/__init__.py
@@ -15,6 +15,7 @@
See docs/topics/cache.txt for information on the public API.
"""
import importlib
+from collections import defaultdict
try:
from urllib.parse import parse_qsl
except ImportError: # Python 2
@@ -138,4 +139,12 @@ def get_cache(backend, **kwargs):
signals.request_finished.connect(cache.close)
return cache
-cache = get_cache(DEFAULT_CACHE_ALIAS)
+class CacheDict(defaultdict):
+ def __missing__(self, key):
+ value = get_cache(key)
+ self[key] = value
+ return value
+
+caches = CacheDict()
+
+cache = caches[DEFAULT_CACHE_ALIAS]
View
26 docs/topics/cache.txt
@@ -679,22 +679,32 @@ pickling.)
Accessing the cache
-------------------
-.. function:: django.core.cache.get_cache(backend, **kwargs)
+.. versionchanged:: 1.7
+
+ The cache module, ``django.core.cache``, provides a dict-like object for
+ accessing the caches defined in :setting:`CACHES`. These are created on
+ demand, and persist for the life of the process.
+
+ >>> from django.core.cache import caches
+ >>> cache = caches['alternate']
+
+If the named key does not exist, ``InvalidCacheBackendError`` will be raised.
-The cache module, ``django.core.cache``, has a ``cache`` object that's
-automatically created from the ``'default'`` entry in the :setting:`CACHES`
-setting::
+The ``default`` cache is still available as ``django.core.cache.cache`` for
+backward compatibility.
>>> from django.core.cache import cache
-If you have multiple caches defined in :setting:`CACHES`, then you can use
-:func:`django.core.cache.get_cache` to retrieve a cache object for any key::
+.. function:: django.core.cache.get_cache(backend, **kwargs)
+
+For creating ad-hoc cache configurations, the
+:func:`django.core.cache.get_cache` method can be passed either a cache name,
+or a backend module and additional configuration options.
>>> from django.core.cache import get_cache
>>> cache = get_cache('alternate')
-If the named key does not exist, ``InvalidCacheBackendError`` will be raised.
-
+Each call to ``get_cache`` will return a new instance of the cache class.
Basic usage
-----------
View
6 tests/cache/liberal_backend.py
@@ -8,3 +8,9 @@ def validate_key(self, key):
class CacheClass(LiberalKeyValidationMixin, LocMemCache):
pass
+class CountingCache(LocMemCache):
+ """A Cache class that tracks how many times it has been instantiated."""
+ count = 0
+ def __init__(self, *args, **kwargs):
+ super(CountingCache, self).__init__(*args, **kwargs)
+ CountingCache.count += 1
View
14 tests/cache/tests.py
@@ -17,7 +17,7 @@
from django.conf import settings
from django.core import management
-from django.core.cache import get_cache
+from django.core.cache import get_cache, caches
from django.core.cache.backends.base import (CacheKeyWarning,
InvalidCacheBackendError)
from django.db import router, transaction
@@ -1120,6 +1120,18 @@ def test_close(self):
signals.request_finished.send(self.__class__)
self.assertTrue(cache.closed)
+ @override_settings(
+ CACHES={'counting': {'BACKEND': 'cache.liberal_backend.CountingCache'}}
+ )
+ def test_caches(self):
+ """
+ Ensure that repeated accesses to caches don't create new cache class
+ instances.
+ """
+ c1 = caches['counting']
+ c2 = caches['counting']
+ self.assertTrue(c1 is c2)
+ self.assertEqual(c1.count, 1)
@override_settings(
CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix',
Something went wrong with that request. Please try again.