mirror of
				https://github.com/django/django.git
				synced 2025-10-28 16:16:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			234 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| =================
 | |
| Class-based views
 | |
| =================
 | |
| 
 | |
| .. versionadded:: 1.3
 | |
| 
 | |
| A view is a callable which takes a request and returns a
 | |
| response. This can be more than just a function, and Django provides
 | |
| an example of some classes which can be used as views. These allow you
 | |
| to structure your views and reuse code by harnessing inheritance and
 | |
| mixins. There are also some generic views for simple tasks which we'll
 | |
| get to later, but you may want to design your own structure of
 | |
| reusable views which suits your use case. For full details, see the
 | |
| :doc:`class-based views reference
 | |
| documentation</ref/class-based-views/index>`.
 | |
| 
 | |
| .. toctree::
 | |
|    :maxdepth: 1
 | |
| 
 | |
|    generic-display
 | |
|    generic-editing
 | |
|    mixins
 | |
| 
 | |
| Basic examples
 | |
| ==============
 | |
| 
 | |
| Django provides base view classes which will suit a wide range of applications.
 | |
| All views inherit from the :class:`~django.views.generic.base.View` class, which
 | |
| handles linking the view in to the URLs, HTTP method dispatching and other
 | |
| simple features. :class:`~django.views.generic.base.RedirectView` is for a simple HTTP
 | |
| redirect, and :class:`~django.views.generic.base.TemplateView` extends the base class
 | |
| to make it also render a template.
 | |
| 
 | |
| 
 | |
| Simple usage
 | |
| ============
 | |
| 
 | |
| Class-based generic views (and any class-based views that inherit from
 | |
| the base classes Django provides) can be configured in two
 | |
| ways: subclassing, or passing in arguments directly in the URLconf.
 | |
| 
 | |
| When you subclass a class-based view, you can override attributes
 | |
| (such as the ``template_name``) or methods (such as ``get_context_data``)
 | |
| in your subclass to provide new values or methods. Consider, for example,
 | |
| a view that just displays one template, ``about.html``. Django has a
 | |
| generic view to do this - :class:`~django.views.generic.base.TemplateView` -
 | |
| so we can just subclass it, and override the template name::
 | |
| 
 | |
|     # some_app/views.py
 | |
|     from django.views.generic import TemplateView
 | |
| 
 | |
|     class AboutView(TemplateView):
 | |
|         template_name = "about.html"
 | |
| 
 | |
| Then, we just need to add this new view into our URLconf. As the class-based
 | |
| views themselves are classes, we point the URL to the ``as_view`` class method
 | |
| instead, which is the entry point for class-based views::
 | |
| 
 | |
|     # urls.py
 | |
|     from django.conf.urls import patterns, url, include
 | |
|     from some_app.views import AboutView
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         (r'^about/', AboutView.as_view()),
 | |
|     )
 | |
| 
 | |
| Alternatively, if you're only changing a few simple attributes on a
 | |
| class-based view, you can simply pass the new attributes into the ``as_view``
 | |
| method call itself::
 | |
| 
 | |
|     from django.conf.urls import patterns, url, include
 | |
|     from django.views.generic import TemplateView
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         (r'^about/', TemplateView.as_view(template_name="about.html")),
 | |
|     )
 | |
| 
 | |
| A similar overriding pattern can be used for the ``url`` attribute on
 | |
| :class:`~django.views.generic.base.RedirectView`.
 | |
| 
 | |
| .. _jsonresponsemixin-example:
 | |
| 
 | |
| More than just HTML
 | |
| -------------------
 | |
| 
 | |
| Where class based views shine is when you want to do the same thing many times.
 | |
| Suppose you're writing an API, and every view should return JSON instead of
 | |
| rendered HTML.
 | |
| 
 | |
| We can use create a mixin class to use in all of our views, handling the
 | |
| conversion to JSON once.
 | |
| 
 | |
| For example, a simple JSON mixin might look something like this::
 | |
| 
 | |
|     import json
 | |
|     from django.http import HttpResponse
 | |
| 
 | |
|     class JSONResponseMixin(object):
 | |
|         """
 | |
|         A mixin that can be used to render a JSON response.
 | |
|         """
 | |
|         response_class = HttpResponse
 | |
| 
 | |
|         def render_to_response(self, context, **response_kwargs):
 | |
|             """
 | |
|             Returns a JSON response, transforming 'context' to make the payload.
 | |
|             """
 | |
|             response_kwargs['content_type'] = 'application/json'
 | |
|             return self.response_class(
 | |
|                 self.convert_context_to_json(context),
 | |
|                 **response_kwargs
 | |
|             )
 | |
| 
 | |
|         def convert_context_to_json(self, context):
 | |
|             "Convert the context dictionary into a JSON object"
 | |
|             # Note: This is *EXTREMELY* naive; in reality, you'll need
 | |
|             # to do much more complex handling to ensure that arbitrary
 | |
|             # objects -- such as Django model instances or querysets
 | |
|             # -- can be serialized as JSON.
 | |
|             return json.dumps(context)
 | |
| 
 | |
| Now we mix this into the base view::
 | |
| 
 | |
|     from django.views.generic import View
 | |
| 
 | |
|     class JSONView(JSONResponseMixin, View):
 | |
|         pass
 | |
| 
 | |
| Equally we could use our mixin with one of the generic views. We can make our
 | |
| own version of :class:`~django.views.generic.detail.DetailView` by mixing
 | |
| :class:`JSONResponseMixin` with the
 | |
| :class:`~django.views.generic.detail.BaseDetailView` -- (the
 | |
| :class:`~django.views.generic.detail.DetailView` before template
 | |
| rendering behavior has been mixed in)::
 | |
| 
 | |
|     class JSONDetailView(JSONResponseMixin, BaseDetailView):
 | |
|         pass
 | |
| 
 | |
| This view can then be deployed in the same way as any other
 | |
| :class:`~django.views.generic.detail.DetailView`, with exactly the
 | |
| same behavior -- except for the format of the response.
 | |
| 
 | |
| If you want to be really adventurous, you could even mix a
 | |
| :class:`~django.views.generic.detail.DetailView` subclass that is able
 | |
| to return *both* HTML and JSON content, depending on some property of
 | |
| the HTTP request, such as a query argument or a HTTP header. Just mix
 | |
| in both the :class:`JSONResponseMixin` and a
 | |
| :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
 | |
| and override the implementation of :func:`render_to_response()` to defer
 | |
| to the appropriate subclass depending on the type of response that the user
 | |
| requested::
 | |
| 
 | |
|     class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
 | |
|         def render_to_response(self, context):
 | |
|             # Look for a 'format=json' GET argument
 | |
|             if self.request.GET.get('format','html') == 'json':
 | |
|                 return JSONResponseMixin.render_to_response(self, context)
 | |
|             else:
 | |
|                 return SingleObjectTemplateResponseMixin.render_to_response(self, context)
 | |
| 
 | |
| Because of the way that Python resolves method overloading, the local
 | |
| ``render_to_response()`` implementation will override the versions provided by
 | |
| :class:`JSONResponseMixin` and
 | |
| :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
 | |
| 
 | |
| For more information on how to use the built in generic views, consult the next
 | |
| topic on :doc:`generic class based views</topics/class-based-views/generic-display>`.
 | |
| 
 | |
| 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, permission_required
 | |
|     from django.views.generic import TemplateView
 | |
| 
 | |
|     from .views import VoteView
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
 | |
|         (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
 | |
|     )
 | |
| 
 | |
| 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-class-based-views:
 | |
| 
 | |
| 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 the
 | |
| :meth:`~django.views.generic.base.View.dispatch` method of the class.
 | |
| 
 | |
| 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. For example::
 | |
| 
 | |
|     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, *args, **kwargs):
 | |
|             return super(ProtectedView, self).dispatch(*args, **kwargs)
 | |
| 
 | |
| In this example, every instance of ``ProtectedView`` will have
 | |
| login protection.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     ``method_decorator`` passes ``*args`` and ``**kwargs``
 | |
|     as parameters to the decorated method on the class. If your method
 | |
|     does not accept a compatible set of parameters it will raise a
 | |
|     ``TypeError`` exception.
 |