From b51086d57313e7ea857f4b96b62d25e600ee0a8d Mon Sep 17 00:00:00 2001 From: Markus Bertheau Date: Mon, 27 Apr 2015 23:56:02 +0200 Subject: [PATCH] [1.8.x] Fixed #13008 -- Added more Cache-Control headers to never_cache() decorator. Backport of 4a438e400b7ce0ab9d0b6876196cbe8d620a4171 from master --- django/utils/cache.py | 1 + docs/releases/1.8.8.txt | 8 ++++++++ tests/decorators/tests.py | 12 ++++++++++++ 3 files changed, 21 insertions(+) diff --git a/django/utils/cache.py b/django/utils/cache.py index e48e159910..66d5e75e40 100644 --- a/django/utils/cache.py +++ b/django/utils/cache.py @@ -134,6 +134,7 @@ def add_never_cache_headers(response): Adds headers to a response to indicate that a page should never be cached. """ patch_response_headers(response, cache_timeout=-1) + patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) def patch_vary_headers(response, newheaders): diff --git a/docs/releases/1.8.8.txt b/docs/releases/1.8.8.txt index e35ed250f5..f3c4e8bba1 100644 --- a/docs/releases/1.8.8.txt +++ b/docs/releases/1.8.8.txt @@ -40,3 +40,11 @@ Bugfixes * Fixed a regression which prevented using a language not in Django's default language list (:setting:`LANGUAGES`) (:ticket:`25915`). + +* ``django.views.decorators.cache.never_cache()`` now sends more persuasive + headers (added ``no-cache, no-store, must-revalidate`` to ``Cache-Control``) + to better prevent caching (:ticket:`13008`). This fixes a problem where a + page refresh in Firefox cleared the selected entries in the admin's + ``filter_horizontal`` and ``filter_vertical`` widgets, which could result + in inadvertent data loss if a user didn't notice that and then submitted the + form (:ticket:`22955`). diff --git a/tests/decorators/tests.py b/tests/decorators/tests.py index a9b5e7a8ae..00d2d85985 100644 --- a/tests/decorators/tests.py +++ b/tests/decorators/tests.py @@ -323,3 +323,15 @@ class XFrameOptionsDecoratorsTests(TestCase): # the middleware's functionality, let's make sure it actually works... r = XFrameOptionsMiddleware().process_response(req, resp) self.assertEqual(r.get('X-Frame-Options', None), None) + + +class NeverCacheDecoratorTest(TestCase): + def test_never_cache_decorator(self): + @never_cache + def a_view(request): + return HttpResponse() + r = a_view(HttpRequest()) + self.assertEqual( + set(r['Cache-Control'].split(', ')), + {'max-age=0', 'no-cache', 'no-store', 'must-revalidate'}, + )