Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #14512 -- Added documentation on how to apply decorators to cla…

…ss-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
  • Loading branch information...
commit 591ad8afbf7a2b32825e81866f387d4eb1938a4e 1 parent ec7c49f
Russell Keith-Magee authored November 20, 2010
6  django/utils/decorators.py
... ...
@@ -1,11 +1,15 @@
1 1
 "Functions that help with dynamically creating decorators for views."
2 2
 
3  
-import types
4 3
 try:
5 4
     from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
6 5
 except ImportError:
7 6
     from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS  # Python 2.4 fallback.
8 7
 
  8
+class classonlymethod(classmethod):
  9
+    def __get__(self, instance, owner):
  10
+        if instance is not None:
  11
+            raise AttributeError("This method is available only on the view class.")
  12
+        return super(classonlymethod, self).__get__(instance, owner)
9 13
 
10 14
 def method_decorator(decorator):
11 15
     """
9  django/views/generic/base.py
... ...
@@ -1,19 +1,12 @@
1  
-import copy
2 1
 from django import http
3 2
 from django.core.exceptions import ImproperlyConfigured
4 3
 from django.template import RequestContext, loader
5  
-from django.utils.translation import ugettext_lazy as _
6 4
 from django.utils.functional import update_wrapper
7 5
 from django.utils.log import getLogger
  6
+from django.utils.decorators import classonlymethod
8 7
 
9 8
 logger = getLogger('django.request')
10 9
 
11  
-class classonlymethod(classmethod):
12  
-    def __get__(self, instance, owner):
13  
-        if instance is not None:
14  
-            raise AttributeError("This method is available only on the view class.")
15  
-        return super(classonlymethod, self).__get__(instance, owner)
16  
-
17 10
 class View(object):
18 11
     """
19 12
     Intentionally simple parent class for all views. Only implements
57  docs/topics/class-based-views.txt
@@ -537,3 +537,60 @@ Because of the way that Python resolves method overloading, the local
537 537
 :func:`render_to_response()` implementation will override the
538 538
 versions provided by :class:`JSONResponseMixin` and
539 539
 :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
  540
+
  541
+Decorating class-based views
  542
+============================
  543
+
  544
+.. highlightlang:: python
  545
+
  546
+The extension of class-based views isn't limited to using mixins. You
  547
+can use also use decorators.
  548
+
  549
+Decorating in URLconf
  550
+---------------------
  551
+
  552
+The simplest way of decorating class-based views is to decorate the
  553
+result of the :meth:`~django.views.generic.base.View.as_view` method.
  554
+The easiest place to do this is in the URLconf where you deploy your
  555
+view::
  556
+
  557
+    from django.contrib.auth.decorators import login_required
  558
+    from django.views.generic import TemplateView
  559
+
  560
+    urlpatterns = patterns('',
  561
+        (r'^about/',login_required(TemplateView.as_view(template_name="secret.html"))),
  562
+    )
  563
+
  564
+This approach applies the decorator on a per-instance basis. If you
  565
+want every instance of a view to be decorated, you need to take a
  566
+different approach.
  567
+
  568
+Decorating the class
  569
+--------------------
  570
+
  571
+To decorate every instance of a class-based view, you need to decorate
  572
+the class definition itself. To do this you apply the decorator to one
  573
+of the view-like methods on the class; that is,
  574
+:meth:`~django.views.generic.base.View.dispatch`, or one of the HTTP
  575
+methods (:meth:`~django.views.generic.base.View.get`,
  576
+:meth:`~django.views.generic.base.View.post` etc).
  577
+
  578
+A method on a class isn't quite the same as a standalone function, so
  579
+you can't just apply a function decorator to the method -- you need to
  580
+transform it into a method decorator first. The ``method_decorator``
  581
+decorator transforms a function decorator into a method decorator so
  582
+that it can be used on an instance method.
  583
+
  584
+    from django.contrib.auth.decorators import login_required
  585
+    from django.utils.decorators import method_decorator
  586
+    from django.views.generic import TemplateView
  587
+
  588
+    class ProtectedView(TemplateView):
  589
+        template_name = 'secret.html'
  590
+
  591
+        @method_decorator(login_required)
  592
+        def dispatch(self, **kwargs):
  593
+            return super(ProtectedView, self).dispatch(**kwargs)
  594
+
  595
+In this example, every instance of :class:`ProtectedView` will have
  596
+login protection.

0 notes on commit 591ad8a

Please sign in to comment.
Something went wrong with that request. Please try again.