Repository: jazzband/django-debug-toolbar

Issue:
Cache Panel reports nothing when the low-level cache API is used
https://github.com/django-debug-toolbar/django-debug-toolbar/issues/5 was closed in 2012 by @jezdez with the comment, "This should be fixed in master." but it is still broken.

The original issue description on google code is still accurate:
http://code.google.com/p/django-debug-toolbar/issues/detail?id=13

Here is a small example that uses Django's cache API and results in a Cache Panel with "0 calls in 0.00ms" on the intercepted redirect:

```
from django.core.cache import cache
from django.http import HttpResponseRedirect

def example_view(request):
    foo = cache.get('bar')
    if foo is None:
        cache.set('bar', 'baz')
        foo = 'baz'
    return HttpResponseRedirect(foo)
```



Discussion:
That may be a regression introduced in version 1.0.

Looking at `CachePanel.enable_instrumentation`, it's pretty clear that the patching strategy doesn't account for such usage.

Well, it's not showing anything for me too

This also doesn't work for me in Django 1.7 using the recommended [`django.core.cache.caches`](https://docs.djangoproject.com/en/dev/topics/cache/#django.core.cache.caches) container.


Resolving patch:
diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py
--- a/debug_toolbar/panels/cache.py
+++ b/debug_toolbar/panels/cache.py
@@ -6,10 +6,18 @@
 
 from django.conf import settings
 from django.core import cache
-from django.core.cache import cache as original_cache, get_cache as original_get_cache
+from django.core.cache import (
+    cache as original_cache,
+    get_cache as original_get_cache)
 from django.core.cache.backends.base import BaseCache
 from django.dispatch import Signal
 from django.utils.translation import ugettext_lazy as _, ungettext
+
+try:
+    from django.core.cache import CacheHandler, caches as original_caches
+except ImportError:  # Django < 1.7
+    CacheHandler = None
+    original_caches = None
 try:
     from collections import OrderedDict
 except ImportError:
@@ -119,6 +127,17 @@ def get_cache(*args, **kwargs):
     return CacheStatTracker(original_get_cache(*args, **kwargs))
 
 
+def get_cache_handler():
+    if CacheHandler is None:
+        return None
+
+    class CacheHandlerPatch(CacheHandler):
+        def __getitem__(self, alias):
+            actual_cache = super(CacheHandlerPatch, self).__getitem__(alias)
+            return CacheStatTracker(actual_cache)
+    return CacheHandlerPatch()
+
+
 class CachePanel(Panel):
     """
     Panel that displays the cache statistics.
@@ -197,11 +216,17 @@ def title(self):
     def enable_instrumentation(self):
         # This isn't thread-safe because cache connections aren't thread-local
         # in Django, unlike database connections.
-        cache.cache = CacheStatTracker(original_cache)
         cache.get_cache = get_cache
+        if CacheHandler is None:
+            cache.cache = CacheStatTracker(original_cache)
+        else:
+            cache.caches = get_cache_handler()
 
     def disable_instrumentation(self):
-        cache.cache = original_cache
+        if CacheHandler is None:
+            cache.cache = original_cache
+        else:
+            cache.caches = original_caches
         cache.get_cache = original_get_cache
 
     def process_response(self, request, response):


Test patch:
diff --git a/tests/panels/test_cache.py b/tests/panels/test_cache.py
--- a/tests/panels/test_cache.py
+++ b/tests/panels/test_cache.py
@@ -2,7 +2,9 @@
 
 from __future__ import absolute_import, unicode_literals
 
+import django
 from django.core import cache
+from django.utils.unittest import skipIf
 
 from ..base import BaseTestCase
 
@@ -24,3 +26,10 @@ def test_recording(self):
         cache.cache.get('foo')
         cache.cache.delete('foo')
         self.assertEqual(len(self.panel.calls), 3)
+
+    @skipIf(django.VERSION < (1, 7), "Caches was added in Django 1.7")
+    def test_recording_caches(self):
+        self.assertEqual(len(self.panel.calls), 0)
+        cache.cache.set('foo', 'bar')
+        cache.caches[cache.DEFAULT_CACHE_ALIAS].get('foo')
+        self.assertEqual(len(self.panel.calls), 2)