index.txt 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. =================
  2. Class-based views
  3. =================
  4. .. versionadded:: 1.3
  5. A view is a callable which takes a request and returns a
  6. response. This can be more than just a function, and Django provides
  7. an example of some classes which can be used as views. These allow you
  8. to structure your views and reuse code by harnessing inheritance and
  9. mixins. There are also some generic views for simple tasks which we'll
  10. get to later, but you may want to design your own structure of
  11. reusable views which suits your use case. For full details, see the
  12. :doc:`class-based views reference
  13. documentation</ref/class-based-views/index>`.
  14. .. toctree::
  15. :maxdepth: 1
  16. generic-display
  17. generic-editing
  18. mixins
  19. Basic examples
  20. ==============
  21. Django provides base view classes which will suit a wide range of applications.
  22. All views inherit from the :class:`~django.views.generic.base.View` class, which
  23. handles linking the view in to the URLs, HTTP method dispatching and other
  24. simple features. :class:`~django.views.generic.base.RedirectView` is for a simple HTTP
  25. redirect, and :class:`~django.views.generic.base.TemplateView` extends the base class
  26. to make it also render a template.
  27. Simple usage
  28. ============
  29. Class-based generic views (and any class-based views that inherit from
  30. the base classes Django provides) can be configured in two
  31. ways: subclassing, or passing in arguments directly in the URLconf.
  32. When you subclass a class-based view, you can override attributes
  33. (such as the ``template_name``) or methods (such as ``get_context_data``)
  34. in your subclass to provide new values or methods. Consider, for example,
  35. a view that just displays one template, ``about.html``. Django has a
  36. generic view to do this - :class:`~django.views.generic.base.TemplateView` -
  37. so we can just subclass it, and override the template name::
  38. # some_app/views.py
  39. from django.views.generic import TemplateView
  40. class AboutView(TemplateView):
  41. template_name = "about.html"
  42. Then, we just need to add this new view into our URLconf. As the class-based
  43. views themselves are classes, we point the URL to the ``as_view`` class method
  44. instead, which is the entry point for class-based views::
  45. # urls.py
  46. from django.conf.urls import patterns, url, include
  47. from some_app.views import AboutView
  48. urlpatterns = patterns('',
  49. (r'^about/', AboutView.as_view()),
  50. )
  51. Alternatively, if you're only changing a few simple attributes on a
  52. class-based view, you can simply pass the new attributes into the ``as_view``
  53. method call itself::
  54. from django.conf.urls import patterns, url, include
  55. from django.views.generic import TemplateView
  56. urlpatterns = patterns('',
  57. (r'^about/', TemplateView.as_view(template_name="about.html")),
  58. )
  59. A similar overriding pattern can be used for the ``url`` attribute on
  60. :class:`~django.views.generic.base.RedirectView`.
  61. .. _jsonresponsemixin-example:
  62. More than just HTML
  63. -------------------
  64. Where class based views shine is when you want to do the same thing many times.
  65. Suppose you're writing an API, and every view should return JSON instead of
  66. rendered HTML.
  67. We can use create a mixin class to use in all of our views, handling the
  68. conversion to JSON once.
  69. For example, a simple JSON mixin might look something like this::
  70. import json
  71. from django.http import HttpResponse
  72. class JSONResponseMixin(object):
  73. """
  74. A mixin that can be used to render a JSON response.
  75. """
  76. response_class = HttpResponse
  77. def render_to_response(self, context, **response_kwargs):
  78. """
  79. Returns a JSON response, transforming 'context' to make the payload.
  80. """
  81. response_kwargs['content_type'] = 'application/json'
  82. return self.response_class(
  83. self.convert_context_to_json(context),
  84. **response_kwargs
  85. )
  86. def convert_context_to_json(self, context):
  87. "Convert the context dictionary into a JSON object"
  88. # Note: This is *EXTREMELY* naive; in reality, you'll need
  89. # to do much more complex handling to ensure that arbitrary
  90. # objects -- such as Django model instances or querysets
  91. # -- can be serialized as JSON.
  92. return json.dumps(context)
  93. Now we mix this into the base view::
  94. from django.views.generic import View
  95. class JSONView(JSONResponseMixin, View):
  96. pass
  97. Equally we could use our mixin with one of the generic views. We can make our
  98. own version of :class:`~django.views.generic.detail.DetailView` by mixing
  99. :class:`JSONResponseMixin` with the
  100. :class:`~django.views.generic.detail.BaseDetailView` -- (the
  101. :class:`~django.views.generic.detail.DetailView` before template
  102. rendering behavior has been mixed in)::
  103. class JSONDetailView(JSONResponseMixin, BaseDetailView):
  104. pass
  105. This view can then be deployed in the same way as any other
  106. :class:`~django.views.generic.detail.DetailView`, with exactly the
  107. same behavior -- except for the format of the response.
  108. If you want to be really adventurous, you could even mix a
  109. :class:`~django.views.generic.detail.DetailView` subclass that is able
  110. to return *both* HTML and JSON content, depending on some property of
  111. the HTTP request, such as a query argument or a HTTP header. Just mix
  112. in both the :class:`JSONResponseMixin` and a
  113. :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
  114. and override the implementation of :func:`render_to_response()` to defer
  115. to the appropriate subclass depending on the type of response that the user
  116. requested::
  117. class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
  118. def render_to_response(self, context):
  119. # Look for a 'format=json' GET argument
  120. if self.request.GET.get('format','html') == 'json':
  121. return JSONResponseMixin.render_to_response(self, context)
  122. else:
  123. return SingleObjectTemplateResponseMixin.render_to_response(self, context)
  124. Because of the way that Python resolves method overloading, the local
  125. ``render_to_response()`` implementation will override the versions provided by
  126. :class:`JSONResponseMixin` and
  127. :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
  128. For more information on how to use the built in generic views, consult the next
  129. topic on :doc:`generic class based views</topics/class-based-views/generic-display>`.
  130. Decorating class-based views
  131. ============================
  132. .. highlightlang:: python
  133. The extension of class-based views isn't limited to using mixins. You
  134. can use also use decorators.
  135. Decorating in URLconf
  136. ---------------------
  137. The simplest way of decorating class-based views is to decorate the
  138. result of the :meth:`~django.views.generic.base.View.as_view` method.
  139. The easiest place to do this is in the URLconf where you deploy your
  140. view::
  141. from django.contrib.auth.decorators import login_required, permission_required
  142. from django.views.generic import TemplateView
  143. from .views import VoteView
  144. urlpatterns = patterns('',
  145. (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
  146. (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
  147. )
  148. This approach applies the decorator on a per-instance basis. If you
  149. want every instance of a view to be decorated, you need to take a
  150. different approach.
  151. .. _decorating-class-based-views:
  152. Decorating the class
  153. --------------------
  154. To decorate every instance of a class-based view, you need to decorate
  155. the class definition itself. To do this you apply the decorator to the
  156. :meth:`~django.views.generic.base.View.dispatch` method of the class.
  157. A method on a class isn't quite the same as a standalone function, so
  158. you can't just apply a function decorator to the method -- you need to
  159. transform it into a method decorator first. The ``method_decorator``
  160. decorator transforms a function decorator into a method decorator so
  161. that it can be used on an instance method. For example::
  162. from django.contrib.auth.decorators import login_required
  163. from django.utils.decorators import method_decorator
  164. from django.views.generic import TemplateView
  165. class ProtectedView(TemplateView):
  166. template_name = 'secret.html'
  167. @method_decorator(login_required)
  168. def dispatch(self, *args, **kwargs):
  169. return super(ProtectedView, self).dispatch(*args, **kwargs)
  170. In this example, every instance of ``ProtectedView`` will have
  171. login protection.
  172. .. note::
  173. ``method_decorator`` passes ``*args`` and ``**kwargs``
  174. as parameters to the decorated method on the class. If your method
  175. does not accept a compatible set of parameters it will raise a
  176. ``TypeError`` exception.