Skip to content

Update the cache panel to support the cache_page decorator. #720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions debug_toolbar/panels/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
get_cache as original_get_cache)
from django.core.cache.backends.base import BaseCache
from django.dispatch import Signal
from django.middleware import cache as middleware_cache
from django.utils.translation import ugettext_lazy as _, ungettext


Expand Down Expand Up @@ -124,17 +125,28 @@ def get_cache(*args, **kwargs):
return CacheStatTracker(original_get_cache(*args, **kwargs))


def get_cache_handler():
if CacheHandler is None:
return None

if CacheHandler is not None:
class CacheHandlerPatch(CacheHandler):
def __getitem__(self, alias):
actual_cache = super(CacheHandlerPatch, self).__getitem__(alias)
return CacheStatTracker(actual_cache)


def get_cache_handler():
if CacheHandler is None:
return None
return CacheHandlerPatch()


# Must monkey patch the middleware's cache module as well in order to
# cover per-view level caching. This needs to be monkey patched outside
# of the enable_instrumentation method since the django's
# decorator_from_middleware_with_args will store the cache from core.caches
# when it wraps the view.
middleware_cache.get_cache = get_cache
middleware_cache.caches = get_cache_handler()


class CachePanel(Panel):
"""
Panel that displays the cache statistics.
Expand Down Expand Up @@ -212,19 +224,24 @@ def title(self):
count) % dict(count=count)

def enable_instrumentation(self):
# This isn't thread-safe because cache connections aren't thread-local
# in Django, unlike database connections.
cache.get_cache = get_cache
if CacheHandler is None:
cache.cache = CacheStatTracker(original_cache)
else:
cache.caches = get_cache_handler()
if isinstance(middleware_cache.caches, CacheHandlerPatch):
cache.caches = middleware_cache.caches
else:
cache.caches = get_cache_handler()

def disable_instrumentation(self):
if CacheHandler is None:
cache.cache = original_cache
else:
cache.caches = original_caches
# While it can be restored to the original, any views that were
# wrapped with the cache_page decorator will continue to use a
# monkey patched cache.
middleware_cache.caches = original_caches
cache.get_cache = original_get_cache

def process_response(self, request, response):
Expand Down
2 changes: 1 addition & 1 deletion docs/panels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Cache

Path: ``debug_toolbar.panels.cache.CachePanel``

Cache queries.
Cache queries. Is incompatible with Django's per-site caching.

Signal
~~~~~~
Expand Down
8 changes: 8 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ def test_middleware_response_insertion(self):
# check toolbar insertion before "</body>"
self.assertContains(resp, '</div>\n</body>')

def test_cache_page(self):
self.client.get('/cached_view/')
self.assertEqual(
len(self.toolbar.get_panel_by_id('CachePanel').calls), 3)
self.client.get('/cached_view/')
self.assertEqual(
len(self.toolbar.get_panel_by_id('CachePanel').calls), 5)


@override_settings(DEBUG=True)
class DebugToolbarIntegrationTestCase(TestCase):
Expand Down
1 change: 1 addition & 0 deletions tests/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
url(r'^non_ascii_request/$', 'regular_view', {'title': NonAsciiRepr()}),
url(r'^new_user/$', 'new_user'),
url(r'^execute_sql/$', 'execute_sql'),
url(r'^cached_view/$', 'cached_view'),
url(r'^__debug__/', include(debug_toolbar.urls)),
)
6 changes: 6 additions & 0 deletions tests/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.cache import cache_page


def execute_sql(request):
Expand All @@ -24,3 +25,8 @@ def new_user(request, username='joe'):
def resolving_view(request, arg1, arg2):
# see test_url_resolving in tests.py
return HttpResponse()


@cache_page(60)
def cached_view(request):
return HttpResponse()