Fixed #14512 -- Added documentation on how to apply decorators to class-based generic views. Thanks to Łukasz Rekucki for his work on the issue.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14642 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2010-11-20 05:10:13 +00:00
parent ec7c49f253
commit 591ad8afbf
3 changed files with 63 additions and 9 deletions

View File

@ -1,11 +1,15 @@
"Functions that help with dynamically creating decorators for views." "Functions that help with dynamically creating decorators for views."
import types
try: try:
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
except ImportError: except ImportError:
from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS # Python 2.4 fallback. 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): def method_decorator(decorator):
""" """

View File

@ -1,19 +1,12 @@
import copy
from django import http from django import http
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django.utils.translation import ugettext_lazy as _
from django.utils.functional import update_wrapper from django.utils.functional import update_wrapper
from django.utils.log import getLogger from django.utils.log import getLogger
from django.utils.decorators import classonlymethod
logger = getLogger('django.request') 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): class View(object):
""" """
Intentionally simple parent class for all views. Only implements Intentionally simple parent class for all views. Only implements

View File

@ -537,3 +537,60 @@ Because of the way that Python resolves method overloading, the local
:func:`render_to_response()` implementation will override the :func:`render_to_response()` implementation will override the
versions provided by :class:`JSONResponseMixin` and versions provided by :class:`JSONResponseMixin` and
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`. :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.