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:
parent
ec7c49f253
commit
591ad8afbf
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue