Author: russellm Date: 2010-11-19 23:10:13 -0600 (Fri, 19 Nov 2010) New Revision: 14642
Modified: django/trunk/django/utils/decorators.py django/trunk/django/views/generic/base.py django/trunk/docs/topics/class-based-views.txt Log: Fixed #14512 -- Added documentation on how to apply decorators to class-based generic views. Thanks to ?\197?\129ukasz Rekucki for his work on the issue. Modified: django/trunk/django/utils/decorators.py =================================================================== --- django/trunk/django/utils/decorators.py 2010-11-20 01:56:34 UTC (rev 14641) +++ django/trunk/django/utils/decorators.py 2010-11-20 05:10:13 UTC (rev 14642) @@ -1,11 +1,15 @@ "Functions that help with dynamically creating decorators for views." -import types try: from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS except ImportError: from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS # Python 2.4 fallback. +class classonlymethod(classmethod): + def __get__(self, instance, owner): + if instance is not None: + raise AttributeError("This method is available only on the view class.") + return super(classonlymethod, self).__get__(instance, owner) def method_decorator(decorator): """ Modified: django/trunk/django/views/generic/base.py =================================================================== --- django/trunk/django/views/generic/base.py 2010-11-20 01:56:34 UTC (rev 14641) +++ django/trunk/django/views/generic/base.py 2010-11-20 05:10:13 UTC (rev 14642) @@ -1,19 +1,12 @@ -import copy from django import http from django.core.exceptions import ImproperlyConfigured from django.template import RequestContext, loader -from django.utils.translation import ugettext_lazy as _ from django.utils.functional import update_wrapper from django.utils.log import getLogger +from django.utils.decorators import classonlymethod logger = getLogger('django.request') -class classonlymethod(classmethod): - def __get__(self, instance, owner): - if instance is not None: - raise AttributeError("This method is available only on the view class.") - return super(classonlymethod, self).__get__(instance, owner) - class View(object): """ Intentionally simple parent class for all views. Only implements Modified: django/trunk/docs/topics/class-based-views.txt =================================================================== --- django/trunk/docs/topics/class-based-views.txt 2010-11-20 01:56:34 UTC (rev 14641) +++ django/trunk/docs/topics/class-based-views.txt 2010-11-20 05:10:13 UTC (rev 14642) @@ -537,3 +537,60 @@ :func:`render_to_response()` implementation will override the versions provided by :class:`JSONResponseMixin` and :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`. + +Decorating class-based views +============================ + +.. highlightlang:: python + +The extension of class-based views isn't limited to using mixins. You +can use also use decorators. + +Decorating in URLconf +--------------------- + +The simplest way of decorating class-based views is to decorate the +result of the :meth:`~django.views.generic.base.View.as_view` method. +The easiest place to do this is in the URLconf where you deploy your +view:: + + from django.contrib.auth.decorators import login_required + from django.views.generic import TemplateView + + urlpatterns = patterns('', + (r'^about/',login_required(TemplateView.as_view(template_name="secret.html"))), + ) + +This approach applies the decorator on a per-instance basis. If you +want every instance of a view to be decorated, you need to take a +different approach. + +Decorating the class +-------------------- + +To decorate every instance of a class-based view, you need to decorate +the class definition itself. To do this you apply the decorator to one +of the view-like methods on the class; that is, +:meth:`~django.views.generic.base.View.dispatch`, or one of the HTTP +methods (:meth:`~django.views.generic.base.View.get`, +:meth:`~django.views.generic.base.View.post` etc). + +A method on a class isn't quite the same as a standalone function, so +you can't just apply a function decorator to the method -- you need to +transform it into a method decorator first. The ``method_decorator`` +decorator transforms a function decorator into a method decorator so +that it can be used on an instance method. + + from django.contrib.auth.decorators import login_required + from django.utils.decorators import method_decorator + from django.views.generic import TemplateView + + class ProtectedView(TemplateView): + template_name = 'secret.html' + + @method_decorator(login_required) + def dispatch(self, **kwargs): + return super(ProtectedView, self).dispatch(**kwargs) + +In this example, every instance of :class:`ProtectedView` will have +login protection. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To post to this group, send email to django-upda...@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-updates?hl=en.