Ticket #11416: 11416-never-cache-admin-views.diff

File 11416-never-cache-admin-views.diff, 7.4 KB (added by Ramiro Morales, 15 years ago)

S slightly modified approach for the patch

  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    a b  
    55from django.contrib.contenttypes.models import ContentType
    66from django.contrib.admin import widgets
    77from django.contrib.admin import helpers
    8 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
     8from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict
    99from django.core.exceptions import PermissionDenied
    1010from django.db import models, transaction
    1111from django.db.models.fields import BLANK_CHOICE_DASH
     
    1818from django.utils.functional import curry
    1919from django.utils.text import capfirst, get_text_list
    2020from django.utils.translation import ugettext as _
    21 from django.utils.translation import ungettext, ugettext_lazy
     21from django.utils.translation import ungettext
    2222from django.utils.encoding import force_unicode
     23from django.views.decorators.cache import never_cache
    2324try:
    2425    set
    2526except NameError:
     
    224225        def wrap(view):
    225226            def wrapper(*args, **kwargs):
    226227                return self.admin_site.admin_view(view)(*args, **kwargs)
    227             return update_wrapper(wrapper, view)
     228            return never_cache(update_wrapper(wrapper, view))
    228229
    229230        info = self.admin_site.name, self.model._meta.app_label, self.model._meta.module_name
    230231
  • django/contrib/admin/sites.py

    diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
    a b  
    1212from django.utils.translation import ugettext_lazy, ugettext as _
    1313from django.views.decorators.cache import never_cache
    1414from django.conf import settings
    15 try:
    16     set
    17 except NameError:
    18     from sets import Set as set     # Python 2.3 fallback
    1915
    2016ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
    2117LOGIN_FORM_KEY = 'this_is_the_login_form'
     
    114110        name = name or action.__name__
    115111        self._actions[name] = action
    116112        self._global_actions[name] = action
    117        
     113
    118114    def disable_action(self, name):
    119115        """
    120116        Disable a globally-registered action. Raises KeyError for invalid names.
    121117        """
    122118        del self._actions[name]
    123        
     119
    124120    def get_action(self, name):
    125121        """
    126122        Explicitally get a registered global action wheather it's enabled or
    127123        not. Raises KeyError for invalid names.
    128124        """
    129125        return self._global_actions[name]
    130    
     126
    131127    def actions(self):
    132128        """
    133129        Get all the enabled actions as an iterable of (name, func).
     
    182178            if not self.has_permission(request):
    183179                return self.login(request)
    184180            return view(request, *args, **kwargs)
    185         return update_wrapper(inner, view)
     181        return never_cache(update_wrapper(inner, view))
    186182
    187183    def get_urls(self):
    188184        from django.conf.urls.defaults import patterns, url, include
  • docs/ref/contrib/admin/index.txt

    diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
    a b  
    757757
    758758.. note::
    759759
    760     Notice that the custom patterns are included *before* the regular admin
     760    Note how we included our custom patterns *before* the regular admin
    761761    URLs: the admin URL patterns are very permissive and will match nearly
    762762    anything, so you'll usually want to prepend your custom URLs to the built-in
    763763    ones.
    764764
    765 Note, however, that the ``self.my_view`` function registered above will *not*
    766 have any permission check done; it'll be accessible to the general public. Since
    767 this is usually not what you want, Django provides a convience wrapper to check
    768 permissions. This wrapper is :meth:`AdminSite.admin_view` (i.e.
    769 ``self.admin_site.admin_view`` inside a ``ModelAdmin`` instance); use it like
    770 so::
     765However, the ``self.my_view`` function registered above suffers from two
     766problems:
     767
     768  * It will *not* have any permission check done; it'll be accessible to the
     769    general public.
     770  * It is not being marked as a non-cacheable and so, if it gets data from the
     771    database, it could show outdated information because of content caching being
     772    applied when the caching middleware is active.
     773
     774Since this is usually not what you want, Django provides a convenience wrapper
     775to check permissions and mark the view as non-cacheable. This wrapper is
     776:meth:`AdminSite.admin_view` (i.e.  ``self.admin_site.admin_view`` inside a
     777``ModelAdmin`` instance); use it like so::
    771778
    772779    class MyModelAdmin(admin.ModelAdmin):
    773780        def get_urls(self):
     
    781788
    782789    (r'^my_view/$', self.admin_site.admin_view(self.my_view))
    783790
    784 This wrapping will protect ``self.my_view`` from unauthorized access.
     791This wrapping will protect ``self.my_view`` from unauthorized access and will
     792apply the ``django.views.decorators.cache.never_cache`` decorator to make sure
     793it is not cached if the cache middleware is active.
    785794
    786795.. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)
    787796
     
    13311340.. versionadded:: 1.1
    13321341
    13331342Just like :class:`ModelAdmin`, :class:`AdminSite` provides a
    1334 :meth:`~django.contrib.admin.ModelAdmin.get_urls()` method
    1335 that can be overridden to define additional views for the site. To add
    1336 a new view to your admin site, extend the base
    1337 :meth:`~django.contrib.admin.ModelAdmin.get_urls()` method to include
    1338 a pattern for your new view.
     1343:meth:`~django.contrib.admin.ModelAdmin.get_urls()` method that can be
     1344overridden to define additional views for the site. To add a new view to your
     1345admin site, extend the base ``get_urls()`` method to include a pattern for your
     1346new view. And, just like it is also described in the
     1347:meth:`~django.contrib.admin.ModelAdmin.get_urls()` section, you will want to
     1348wrap your custom view with the
     1349:meth:`~django.contrib.admin.AdminSite.admin_view()` :class:`AdminSite` method
     1350to get access control and never-caching features for it.
    13391351
    13401352.. note::
    13411353    Any view you render that uses the admin templates, or extends the base
  • tests/regressiontests/admin_views/tests.py

    diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
    a b  
    5454        response = self.client.get('/test_admin/%s/admin_views/section/add/' % self.urlbit)
    5555        self.failUnlessEqual(response.status_code, 200)
    5656
     57    def testMaxAgeModelAdminView(self):
     58        """
     59        Because cache time can be set by middleware, ensure max-age is explicity 0
     60        (non-model-specific view)
     61        """
     62        response = self.client.get('/test_admin/%s/admin_views/' % self.urlbit)
     63
     64        from django.utils.cache import get_max_age
     65        self.failUnlessEqual(get_max_age(response), 0)
     66
     67    def testMaxAgeModelView(self):
     68        """
     69        Because cache time can be set by middleware, ensure max-age is explicity 0
     70        (model-specific view)
     71        """
     72        response = self.client.get('/test_admin/%s/admin_views/section/add/' % self.urlbit)
     73
     74        from django.utils.cache import get_max_age
     75        self.failUnlessEqual(get_max_age(response), 0)
     76
    5777    def testAddWithGETArgs(self):
    5878        response = self.client.get('/test_admin/%s/admin_views/section/add/' % self.urlbit, {'name': 'My Section'})
    5979        self.failUnlessEqual(response.status_code, 200)
Back to Top