diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/index.txt | 6 | ||||
| -rw-r--r-- | docs/internals/deprecation.txt | 9 | ||||
| -rw-r--r-- | docs/intro/tutorial04.txt | 140 | ||||
| -rw-r--r-- | docs/ref/class-based-views.txt | 1391 | ||||
| -rw-r--r-- | docs/ref/generic-views.txt | 2 | ||||
| -rw-r--r-- | docs/ref/index.txt | 10 | ||||
| -rw-r--r-- | docs/releases/1.3.txt | 29 | ||||
| -rw-r--r-- | docs/topics/class-based-views.txt | 535 | ||||
| -rw-r--r-- | docs/topics/generic-views-migration.txt | 127 | ||||
| -rw-r--r-- | docs/topics/index.txt | 10 |
10 files changed, 2186 insertions, 73 deletions
diff --git a/docs/index.txt b/docs/index.txt index b743176a84..e456d047ec 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -103,8 +103,8 @@ The view layer :doc:`Custom storage <howto/custom-file-storage>` * **Generic views:** - :doc:`Overview<topics/generic-views>` | - :doc:`Built-in generic views<ref/generic-views>` + :doc:`Overview<topics/class-based-views>` | + :doc:`Built-in generic views<ref/class-based-views>` * **Advanced:** :doc:`Generating CSV <howto/outputting-csv>` | @@ -189,6 +189,8 @@ Other batteries included * :doc:`Unicode in Django <ref/unicode>` * :doc:`Web design helpers <ref/contrib/webdesign>` * :doc:`Validators <ref/validators>` + * Function-based generic views (Deprecated) :doc:`Overview<topics/generic-views>` | :doc:`Built-in generic views<ref/generic-views>` | :doc:`Migration guide<topics/generic-views-migration>` + The Django open-source project ============================== diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index c227f9ab5c..c1341e03fa 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -118,6 +118,15 @@ their deprecation, as per the :ref:`Django deprecation policy :func:`django.contrib.formtools.utils.security_hash` is deprecated, in favour of :func:`django.contrib.formtools.utils.form_hmac` + * The function-based generic views have been deprecated in + favor of their class-based cousins. The following modules + will be removed: + + * :mod:`django.views.generic.create_update` + * :mod:`django.views.generic.date_based` + * :mod:`django.views.generic.list_detail` + * :mod:`django.views.generic.simple` + * 2.0 * ``django.views.defaults.shortcut()``. This function has been moved to ``django.contrib.contenttypes.views.shortcut()`` as part of the diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt index dfbd82df55..9568546291 100644 --- a/docs/intro/tutorial04.txt +++ b/docs/intro/tutorial04.txt @@ -232,6 +232,7 @@ tutorial so far:: Change it like so:: from django.conf.urls.defaults import * + from django.views.generic import DetailView, ListView from polls.models import Poll info_dict = { @@ -239,88 +240,91 @@ Change it like so:: } urlpatterns = patterns('', - (r'^$', 'django.views.generic.list_detail.object_list', info_dict), - (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict), - url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'), + (r'^$', + ListView.as_view( + models=Poll, + context_object_name='latest_poll_list' + template_name='polls/index.html')), + (r'^(?P<pk>\d+)/$', + DetailView.as_view( + models=Poll, + template_name='polls/detail.html')), + url(r'^(?P<pk>\d+)/results/$', + DetailView.as_view( + models=Poll, + template_name='polls/results.html'), + 'poll_results'), (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ) We're using two generic views here: -:func:`~django.views.generic.list_detail.object_list` and -:func:`~django.views.generic.list_detail.object_detail`. Respectively, those two -views abstract the concepts of "display a list of objects" and "display a detail -page for a particular type of object." +:class:`~django.views.generic.list.ListView` and +:class:`~django.views.generic.detail.DetailView`. Respectively, those +two views abstract the concepts of "display a list of objects" and +"display a detail page for a particular type of object." - * Each generic view needs to know what data it will be acting upon. This - data is provided in a dictionary. The ``queryset`` key in this dictionary - points to the list of objects to be manipulated by the generic view. + * Each generic view needs to know what model it will be acting + upon. This is provided using the ``model`` parameter. - * The :func:`~django.views.generic.list_detail.object_detail` generic view - expects the ID value captured from the URL to be called ``"object_id"``, - so we've changed ``poll_id`` to ``object_id`` for the generic views. + * The :class:`~django.views.generic.list.DetailView` generic view + expects the primary key value captured from the URL to be called + ``"pk"``, so we've changed ``poll_id`` to ``pk`` for the generic + views. - * We've added a name, ``poll_results``, to the results view so that we have - a way to refer to its URL later on (see the documentation about - :ref:`naming URL patterns <naming-url-patterns>` for information). We're - also using the :func:`~django.conf.urls.default.url` function from + * We've added a name, ``poll_results``, to the results view so + that we have a way to refer to its URL later on (see the + documentation about :ref:`naming URL patterns + <naming-url-patterns>` for information). We're also using the + :func:`~django.conf.urls.default.url` function from :mod:`django.conf.urls.defaults` here. It's a good habit to use - :func:`~django.conf.urls.defaults.url` when you are providing a pattern - name like this. + :func:`~django.conf.urls.defaults.url` when you are providing a + pattern name like this. -By default, the :func:`~django.views.generic.list_detail.object_detail` generic -view uses a template called ``<app name>/<model name>_detail.html``. In our -case, it'll use the template ``"polls/poll_detail.html"``. Thus, rename your -``polls/detail.html`` template to ``polls/poll_detail.html``, and change the -:func:`~django.shortcuts.render_to_response` line in ``vote()``. +By default, the :class:`~django.views.generic.list.DetailView` generic +view uses a template called ``<app name>/<model name>_detail.html``. +In our case, it'll use the template ``"polls/poll_detail.html"``. The +``template_name`` argument is used to tell Django to use a specific +template name instead of the autogenerated default template name. We +also specify the ``template_name`` for the ``results`` list view -- +this ensures that the results view and the detail view have a +different appearance when rendered, even though they're both a +:class:`~django.views.generic.list.DetailView` behind the scenes. -Similarly, the :func:`~django.views.generic.list_detail.object_list` generic -view uses a template called ``<app name>/<model name>_list.html``. Thus, rename -``polls/index.html`` to ``polls/poll_list.html``. +Similarly, the :class:`~django.views.generic.list.ListView` generic +view uses a default template called ``<app name>/<model +name>_list.html``; we use ``template_name`` to tell +:class:`~django.views.generic.list.ListView` to use our existing +``"polls/index.html"`` template. -Because we have more than one entry in the URLconf that uses -:func:`~django.views.generic.list_detail.object_detail` for the polls app, we -manually specify a template name for the results view: -``template_name='polls/results.html'``. Otherwise, both views would use the same -template. Note that we use ``dict()`` to return an altered dictionary in place. +In previous parts of the tutorial, the templates have been provided +with a context that contains the ``poll`` and ``latest_poll_list`` +context variables. For DetailView the ``poll`` variable is provided +automatically -- since we're using a Django model (``Poll``), Django +is able to determine an appropriate name for the context variable. +However, for ListView, the automatically generated context variable is +``poll_list``. To override this we provide the ``context_object_name`` +option, specifying that we want to use ``latest_poll_list`` instead. +As an alternative approach, you could change your templates to match +the new default context variables -- but it's a lot easier to just +tell Django to use the variable you want. -.. note:: :meth:`django.db.models.QuerySet.all` is lazy +You can now delete the ``index()``, ``detail()`` and ``results()`` +views from ``polls/views.py``. We don't need them anymore -- they have +been replaced by generic views. - It might look a little frightening to see ``Poll.objects.all()`` being used - in a detail view which only needs one ``Poll`` object, but don't worry; - ``Poll.objects.all()`` is actually a special object called a - :class:`~django.db.models.QuerySet`, which is "lazy" and doesn't hit your - database until it absolutely has to. By the time the database query happens, - the :func:`~django.views.generic.list_detail.object_detail` generic view - will have narrowed its scope down to a single object, so the eventual query - will only select one row from the database. +The ``vote()`` view is still required. However, it must be modified to +match the new context variables. In the +:func:`~django.shortcuts.render_to_response` call, rename the ``poll`` +context variable to ``object``. - If you'd like to know more about how that works, The Django database API - documentation :ref:`explains the lazy nature of QuerySet objects - <querysets-are-lazy>`. - -In previous parts of the tutorial, the templates have been provided with a -context that contains the ``poll`` and ``latest_poll_list`` context variables. -However, the generic views provide the variables ``object`` and ``object_list`` -as context. Therefore, you need to change your templates to match the new -context variables. Go through your templates, and modify any reference to -``latest_poll_list`` to ``object_list``, and change any reference to ``poll`` -to ``object``. - -You can now delete the ``index()``, ``detail()`` and ``results()`` views -from ``polls/views.py``. We don't need them anymore -- they have been replaced -by generic views. - -The ``vote()`` view is still required. However, it must be modified to match the -new context variables. In the :func:`~django.shortcuts.render_to_response` call, -rename the ``poll`` context variable to ``object``. - -The last thing to do is fix the URL handling to account for the use of generic -views. In the vote view above, we used the -:func:`~django.core.urlresolvers.reverse` function to avoid hard-coding our -URLs. Now that we've switched to a generic view, we'll need to change the -:func:`~django.core.urlresolvers.reverse` call to point back to our new generic -view. We can't simply use the view function anymore -- generic views can be (and -are) used multiple times -- but we can use the name we've given:: +The last thing to do is fix the URL handling to account for the use of +generic views. In the vote view above, we used the +:func:`~django.core.urlresolvers.reverse` function to avoid +hard-coding our URLs. Now that we've switched to a generic view, we'll +need to change the :func:`~django.core.urlresolvers.reverse` call to +point back to our new generic view. We can't simply use the view +function anymore -- generic views can be (and are) used multiple times +-- but we can use the name we've given:: return HttpResponseRedirect(reverse('poll_results', args=(p.id,))) diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt new file mode 100644 index 0000000000..4f800e1fd9 --- /dev/null +++ b/docs/ref/class-based-views.txt @@ -0,0 +1,1391 @@ +========================= +Class-Based Generic views +========================= + +.. versionadded:: 1.3 + +.. note:: + Prior to Django 1.3, generic views were implemented as functions. The + function-based implementation has been deprecated in favor of the + class-based approach described here. + + For the reference to the old on details on the old implementation, + see the :doc:`topic guide </topics/generic-views>` and + :doc:`detailed reference </topics/generic-views>`. + +Writing Web applications can be monotonous, because we repeat certain patterns +again and again. In Django, the most common of these patterns have been +abstracted into "generic views" that let you quickly provide common views of +an object without actually needing to write any Python code. + +A general introduction to generic views can be found in the :doc:`topic guide +</topics/class-based-views>`. + +This reference contains details of Django's built-in generic views, along with +a list of all keyword arguments that a generic view expects. Remember that +arguments may either come from the URL pattern or from the ``extra_context`` +additional-information dictionary. + +Most generic views require the ``queryset`` key, which is a ``QuerySet`` +instance; see :doc:`/topics/db/queries` for more information about ``QuerySet`` +objects. + +Mixins +====== + +A mixin class is a way of using the inheritance capabilities of +classes to compose a class out of smaller pieces of behavior. Django's +class-based generic views are constructed by composing a mixins into +usable generic views. + +For example, the :class:`~django.views.generic.base.detail.DetailView` +is composed from: + + * :class:`~django.db.views.generic.base.View`, which provides the + basic class-based behavior + * :class:`~django.db.views.generic.detail.SingleObjectMixin`, which + provides the utilities for retrieving and displaying a single object + * :class:`~django.db.views.generic.detail.SingleObjectTemplateResponseMixin`, + which provides the tools for rendering a single object into a + template-based response. + +When combined, these mixins provide all the pieces necessary to +provide a view over a single object that renders a template to produce +a response. + +When the documentation for a view gives the list of mixins, that view +inherits all the properties and methods of that mixin. + +Django provides a range of mixins. If you want to write your own +generic views, you can build classes that compose these mixins in +interesting ways. Alternatively, you can just use the pre-mixed +`Generic views`_ that Django provides. + +Simple mixins +------------- + +.. currentmodule:: django.views.generic.base + +TemplateResponseMixin +~~~~~~~~~~~~~~~~~~~~~ +.. class:: TemplateResponseMixin() + +**Attributes** + +.. attribute:: TemplateResponseMixin.template_name + + The path to the template to use when rendering the view. + +**Methods** + +.. method:: TemplateResponseMixin.render_to_response(context) + + Returns a full composed HttpResponse instance, ready to be + returned to the user. + + Calls, :meth:`~TemplateResponseMixin.render_template()` to build + the content of the response, and + :meth:`~TemplateResponseMixin.get_response()` to construct the + :class:`~django.http.HttpResponse` object. + +.. method:: TemplateResponseMixin.get_response(content, **httpresponse_kwargs) + + Constructs the :class:`~django.http.HttpResponse` object around + the given content. If any keyword arguments are provided, they + will be passed to the constructor of the + :class:`~django.http.HttpResponse` instance. + +.. method:: TemplateResponseMixin.render_template(context) + + Calls :meth:`~TemplateResponseMixin.get_context_instance()` to + obtain the :class:`Context` instance to use for rendering, and + calls :meth:`TemplateReponseMixin.get_template()` to load the + template that will be used to render the final content. + +.. method:: TemplateResponseMixin.get_context_instance(context) + + Turns the data dictionary ``context`` into an actual context + instance that can be used for rendering. + + By default, constructs a :class:`~django.template.RequestContext` + instance. + +.. method:: TemplateResponseMixin.get_template() + + Calls :meth:`~TemplateResponseMixin.get_template_names()` to + obtain the list of template names that will be searched looking + for an existent template. + +.. method:: TemplateResponseMixin.get_template_names() + + The list of template names to search for when rendering the + template. + + If :attr:`TemplateResponseMixin.template_name` is specified, the + default implementation will return a list containing + :attr:`TemplateResponseMixin.template_name` (if it is specified). + +.. method:: TemplateResponseMixin.load_template(names) + + Loads and returns a template found by searching the list of + ``names`` for a match. Uses Django's default template loader. + +Single object mixins +-------------------- + +.. currentmodule:: django.views.generic.detail + +SingleObjectMixin +~~~~~~~~~~~~~~~~~ +.. class:: SingleObjectMixin() + +**Attributes** + +.. attribute:: SingleObjectMixin.model + + The model that this view will display data for. Specifying ``model + = Foo`` is effectively the same as specifying ``queryset = + Foo.objects.all()``. + +.. attribute:: SingleObjectMixin.queryset + + A ``QuerySet`` that represents the objects. If provided, the + value of :attr:`SingleObjectMixin.queryset` supersedes the + value provided for :attr:`SingleObjectMixin.model`. + +.. attribute:: SingleObjectMixin.slug_field + + The name of the field on the model that contains the slug. By + default, ``slug_field`` is ``'slug'``. + +.. attribute:: SingleObjectMixin.context_object_name + + Designates the name of the variable to use in the context. + +**Methods** + +.. method:: SingleObjectMixin.get_queryset() + + Returns the queryset that will be used to retrieve the object that + this view will display. + +.. method:: SingleObjectMixin.get_context_object_name(object_list) + + Return the context variable name that will be used to contain the + list of data that this view is manipulating. If object_list is a + queryset of Django objects, the context name will be verbose + plural name of the model that the queryset is composed from. + +.. method:: SingleObjectMixin.get_context_data(**kwargs) + + Returns context data for displaying the list of objects. + +**Context** + + * ``object``: The object that this view is displaying. If + ``context_object_name`` is specified, that variable will also be + set in the context, with the same value as ``object``. + +SingleObjectTemplateResponseMixin +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: SingleObjectTemplateResponseMixin() + +A mixin class that performs template-based response rendering for +views that operate upon a single object instance. Requires that the +view it is mixed with provides ``self.object``, the object instance +that the view is operating on. ``self.object`` will usually be, but is +not required to be, an instance of a Django model. It may be ``None`` +if the view is in the process of constructing a new instance. + +**Extends** + + * :class:`~django.views.generic.base.TemplateResponseMixin` + +**Attributes** + +.. attribute:: SingleObjectTemplateResponseMixin.template_name_field + + The field on the current object instance that can be used to + determine the name of a candidate template. If either + ``template_name_field`` or the value of the + ``template_name_field`` on the current object instance is + ``None``, the object will not be interrogated for a candidate + template name. + +.. attribute:: SingleObjectTemplateResponseMixin.template_name_suffix + + The suffix to append to the auto-generated candidate template name. + Default suffix is ``_detail``. + +**Methods** + +.. method:: SingleObjectTemplateResponseMixin.get_template_names() + + Returns a list of candidate template names. Returns the following + list: + + * the value of ``template_name`` on the view (if provided) + * the contents of the ``template_name_field`` field on the + object instance that the view is operating upon (if available) + * ``<app_label>/<object_name><template_name_suffix>.html`` + +Multiple object mixins +---------------------- + +.. currentmodule:: django.views.generic.list + +MultipleObjectMixin +~~~~~~~~~~~~~~~~~~~ +.. class:: MultipleObjectMixin() + +A mixin that can be used to display a list of objects. + +If ``paginate_by`` is specified, Django will paginate the results +returned by this. You can specify the page number in the URL in one of +two ways: + + * Use the ``page`` parameter in the URLconf. For example, this is + what your URLconf might look like:: + + (r'^objects/page(?P<page>[0-9]+)/$', PaginatedView.as_view()) + + * Pass the page number via the ``page`` query-string parameter. For + example, a URL would look like this:: + + /objects/?page=3 + +These values and lists are 1-based, not 0-based, so the first page +would be represented as page ``1``. + +For more on pagination, read the :doc:`pagination documentation +</topics/pagination>`. + +As a special case, you are also permitted to use ``last`` as a value +for ``page``:: + + /objects/?page=last + +This allows you to access the final page of results without first +having to determine how many pages there are. + +Note that ``page`` *must* be either a valid page number or the value +``last``; any other value for ``page`` will result in a 404 error. + +**Attributes** + +.. attribute:: MultipleObjectMixin.allow_empty + + A boolean specifying whether to display the page if no objects are + available. If this is ``False`` and no objects are available, the + view will raise a 404 instead of displaying an empty page. By + default, this is ``True``. + +.. attribute:: MultipleObjectMixin.model + + The model that this view will display data for. Specifying ``model + = Foo`` is effectively the same as specifying ``queryset = + Foo.objects.all()``. + +.. attribute:: MultipleObjectMixin.queryset + + A ``QuerySet`` that represents the objects. If provided, the + value of :attr:`MultipleObjectMixin.queryset` supersedes the + value provided for :attr:`MultipleObjectMixin.model`. + +.. attribute:: MultipleObjectMixin.paginate_by + + An integer specifying how many objects should be displayed per + page. If this is given, the view will paginate objects with + :attr:`MultipleObjectMixin.paginate_by` objects per page. The view + will expect either a ``page`` query string parameter (via ``GET``) + or a ``page`` variable specified in the URLconf. + +.. attribute:: MultipleObjectMixin.context_object_name + + Designates the name of the variable to use in the context. + +**Methods** + +.. method:: MultipleObjectMixin.get_queryset() + + Returns the queryset that represents the data this view will display. + +.. method:: MultipleObjectMixin.paginate_queryset(queryset, page_size) + + Returns a 4-tuple containing:: + + (``paginator``, ``page``, ``object_list``, ``is_paginated``) + + constructed by paginating ``queryset`` into pages of size ``page_size``. + If the request contains a ``page`` argument, either as a captured + URL argument or as a GET argument, ``object_list`` will correspond + to the objects from that page. + +.. method:: MultipleObjectMixin.get_paginate_by(queryset) + +.. method:: MultipleObjectMixin.get_allow_empty() + + Return a boolean specifying whether to display the page if no objects are + available. If this method returns ``False`` and no objects are available, the + view will raise a 404 instead of displaying an empty page. By + default, this is ``True``. + +.. method:: MultipleObjectMixin.get_context_object_name(object_list) + + Return the context variable name that will be used to contain the + list of data that this view is manipulating. If object_list is a + queryset of Django objects, the context name will be verbose + plural name of the model that the queryset is composed from. + +.. method:: MultipleObjectMixin.get_context_data(**kwargs) + + Returns context data for displaying the list of objects. + +**Context** + + * ``object_list``: The list of object that this view is + displaying. If ``context_object_name`` is specified, that + variable will also be set in the context, with the same value as + ``object_list``. + + * ``is_paginated``: A boolean representing whether the results are + paginated. Specifically, this is set to ``False`` if no page + size has been specified, or if the number of available objects + is less than or equal to ``paginate_by``. + + * ``paginator``: An instance of + :class:`django.core.paginator.Paginator`. If the page is not + paginated, this context variable will be ``None`` + + * ``page_obj``: An instance of + :class:`django.core.paginator.Page`. If the page is not + paginated, this context variable will be ``None`` + +MultipleObjectTemplateResponseMixin +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. class:: MultipleObjectTemplateResponseMixin() + +A mixin class that performs template-based response rendering for +views that operate upon a list of object instances. Requires that the +view it is mixed with provides ``self.object_list``, the list of +object instances that the view is operating on. ``self.object_list`` +may be, but is not required to be, a +:class:`~django.db.models.Queryset`. + +**Extends** + + * :class:`~django.views.generic.base.TemplateResponseMixin` + +**Attributes** + +.. attribute:: MultipleObjectTemplateResponseMixin.template_name_suffix + + The suffix to append to the auto-generated candidate template name. + Default suffix is ``_list``. + +**Methods** + +.. method:: MultipleObjectTemplateResponseMixin.get_template_names() + + Returns a list of candidate template names. Returns the following + list: + + * the value of ``template_name`` on the view (if provided) + * ``<app_label>/<object_name><template_name_suffix>.html`` + +Editing mixins +-------------- + +.. currentmodule:: django.views.generic.edit + +FormMixin +~~~~~~~~~ +.. class:: FormMixin() + +A mixin class that provides facilities for creating and displaying forms. + +**Attributes** + +.. attribute:: FormMixin.initial + + A dictionary containing initial data for the form. + +.. attribute:: FormMixin.form_class + + The form class to instantiate. + +.. attribute:: FormMixin.success_url + + The URL to redirect to when the form is successfully processed. + +**Methods** + +.. method:: FormMixin.get_initial() + + Retrieve initial data for the form. By default, returns + :attr:`FormMixin.initial`. + +.. method:: FormMixin.get_form_class() + + Retrieve the form class to instantiate. By default, + :attr:`FormMixin.form_class`. + +.. method:: FormMixin.get_form(form_class) + + Instantiate an instance of ``form_class``. If the request is a + ``POST`` or ``PUT``, the request data (``request.POST`` and + ``request.FILES``) will be provided to the form at time of + construction + +.. method:: FormMixin.get_success_url() + + Determine the URL to redirect to when the form is successfully + validated. Returns :attr:`FormMixin.success_url` by default. + +.. method:: FormMixin.form_valid() + + Redirects to :attr:`ModelFormMixin.success_url`. + +.. method:: FormMixin.form_invalid() + + Renders a response, providing the invalid form as context. + +.. method:: FormMixin.get_context_data(**kwargs) + + Populates a context containing the contents of ``kwargs``. + +**Context** + + * ``form``: The form instance that was generated for the view. + +**Notes** + + * Views mixing :class:`~django.views.generic.edit.FormMixin` must + provide an implementation of :meth:`~FormMixin.form_valid()` and + :meth:`~FormMixin.form_invalid()`. + +ModelFormMixin +~~~~~~~~~~~~~~ +.. class:: ModelFormMixin() + +A form mixin that works on ModelForms, rather than a standalone form. + +Since this is a subclass of +:class:`~django.views.generic.detail.SingleObjectMixin`, instances of +this mixin have access to the :attr:`~SingleObjectMixin.model`` and +:attr:`~SingleObjectMixin.queryset`` attributes, describing the type of +object that the ModelForm is manipulating. The view also provides +``self.object``, the instance being manipulated. If the instance is +being created, ``self.object`` will be ``None`` + +**Mixins** + + * :class:`django.views.generic.forms.FormMixin` + * :class:`django.views.generic.detail.SingleObjectMixin` + +**Attributes** + +.. attribute:: ModelFormMixin.success_url + + The URL to redirect to when the form is successfully processed. + +**Methods** + +.. method:: ModelFormMixin.get_form_class() + + Retrieve the form class to instantiate. If + :attr:`FormMixin.form_class` is provided, that class will be used. + Otherwise, a ModelForm will be instantiated using the model + associated with the :attr:`~SingleObjectMixin.queryset``, or with + the :attr:`~SingleObjectMixin.model``, depending on which + attribute is provided. + +.. method:: FormMixin.get_form(form_class) + + Instantiate an instance of ``form_class``. If the request is a + ``POST`` or ``PUT``, the request data (``request.POST`` and + ``request.FILES``) will be provided to the form at time of + construction. The current instance (``self.object``) will also + be provided. + +.. method:: ModelFormMixin.get_success_url() + + Determine the URL to redirect to when the form is successfully + validated. Returns :attr:`FormMixin.success_url` if it is + provided; otherwise, attempts to use the ``get_absolute_url()`` + of the object. + +.. method:: ModelFormMixin.form_valid() + + Saves the form instance, sets the current object for the view, + and redirects to :attr:`ModelFormMixin.success_url`. + +.. method:: ModelFormMixin.form_invalid() + + Renders a response, providing the invalid form as context. + +ProcessFormView +~~~~~~~~~~~~~~~ +.. class:: ProcessFormView() + +A mixin that provides basic HTTP GET and POST workflow. + +On GET: + * Construct a form + * Render a response using a context that contains that form + +On POST: + * Construct a form + * Check the form for validity, and handle accordingly. + +The PUT action is also handled, as an analog of POST. + +DeletionMixin +~~~~~~~~~~~~~ +.. class:: DeletionMixin() + +Enables handling of the ``DELETE`` http action. + +**Attributes** + +.. attribute:: DeletionMixin.success_url + + The url to redirect to when the nominated object has been + successfully deleted. + +**Methods** + +.. attribute:: DeletionMixin.get_success_url(obj) + + Returns the url to redirect to when the nominated object has been + successfully deleted. Returns + :attr:`~django.views.generic.edit.DeletionMixin.success_url` by + default. + +Date-based mixins +----------------- + +.. currentmodule:: django.views.generic.dates + +YearMixin +~~~~~~~~~ +.. class:: YearMixin() + +A mixin that can be used to retrieve and provide parsing information +for a year component of a date. + +**Attributes** + +.. attribute:: YearMixin.year_format + + The strftime_ format to use when parsing the year. By default, + this is ``'%Y'``. + +.. _strftime: http://docs.python.org/library/time.html#time.strftime + +.. attribute:: YearMixin.year + + **Optional** The value for the year (as a string). By default, + set to ``None``, which means the year will be determined using + other means. + +**Methods** + +.. method:: YearMixin.get_year_format() + + Returns the strftime_ format to use when parsing the year. Returns + :attr:`YearMixin.year_format` by default. + +.. method:: YearMixin.get_year() + + Returns the year for which this view will display data. Tries the + following sources, in order: + + * The value of the :attr:`YearMixin.year` attribute. + * The value of the `year` argument captured in the URL pattern + * The value of the `year` GET query argument. + + Raises a 404 if no valid year specification can be found. + +MonthMixin +~~~~~~~~~~ +.. class:: MonthMixin() + +A mixin that can be used to retrieve and provide parsing information +for a month component of a date. + +**Attributes** + +.. attribute:: MonthMixin.month_format + + The strftime_ format to use when parsing the month. By default, + this is ``'%b'``. + +.. attribute:: MonthMixin.month + + **Optional** The value for the month (as a string). By default, + set to ``None``, which means the month will be determined using + other means. + +**Methods** + +.. method:: MonthMixin.get_month_format() + + Returns the strftime_ format to use when parsing the month. Returns + :attr:`MonthMixin.month_format` by default. + +.. method:: MonthMixin.get_month() + + Returns the month for which this view will display data. Tries the + following sources, in order: + + * The value of the :attr:`MonthMixin.month` attribute. + * The value of the `month` argument captured in the URL pattern + * The value of the `month` GET query argument. + + Raises a 404 if no valid month specification can be found. + +.. method:: MonthMixin.get_next_month(date) + + Returns a date object containing the first day of the month after + the date provided. Returns `None`` if mixed with a view that sets + ``allow_future = False``, and the next month is in the future. + If ``allow_empty = False``, returns the next month that contains + data. + +.. method:: MonthMixin.get_prev_month(date) + + Returns a date object containing the first day of the month before + the date provided. If ``allow_empty = False``, returns the previous + month that contained data. + +DayMixin +~~~~~~~~~ +.. class:: DayMixin() + +A mixin that can be used to retrieve and provide parsing information +for a day component of a date. + +**Attributes** + +.. attribute:: DayMixin.day_format + + The strftime_ format to use when parsing the day. By default, + this is ``'%d'``. + +.. attribute:: DayMixin.day + + **Optional** The value for the day (as a string). By default, + set to ``None``, which means the day will be determined using + other means. + +**Methods** + +.. method:: DayMixin.get_day_format() + + Returns the strftime_ format to use when parsing the day. Returns + :attr:`DayMixin.day_format` by default. + +.. method:: DayMixin.get_day() + + Returns the day for which this view will display data. Tries the + following sources, in order: + + * The value of the :attr:`DayMixin.day` attribute. + * The value of the `day` argument captured in the URL pattern + * The value of the `day` GET query argument. + + Raises a 404 if no valid day specification can be found. + +.. method:: MonthMixin.get_next_day(date) + + Returns a date object containing the next day after the date + provided. Returns `None`` if mixed with a view that sets + ``allow_future = False``, and the next day is in the future. If + ``allow_empty = False``, returns the next day that contains + data. + +.. method:: MonthMixin.get_prev_day(date) + + Returns a date object containing the previous day. If + ``allow_empty = False``, returns the previous day that contained + data. + +WeekMixin +~~~~~~~~~ +.. class:: WeekMixin() + +A mixin that can be used to retrieve and provide parsing information +for a week component of a date. + +**Attributes** + +.. attribute:: WeekMixin.week_format + + The strftime_ format to use when parsing the week. By default, + this is ``'%U'``. + +.. attribute:: WeekMixin.week + + **Optional** The value for the week (as a string). By default, + set to ``None``, which means the week will be determined using + other means. + +**Methods** + +.. method:: WeekMixin.get_week_format() + + Returns the strftime_ format to use when parsing the week. Returns + :attr:`WeekMixin.week_format` by default. + +.. method:: WeekMixin.get_week() + + Returns the week for which this view will display data. Tries the + following sources, in order: + + * The value of the :attr:`WeekMixin.week` attribute. + * The value of the `week` argument captured in the URL pattern + * The value of the `week` GET query argument. + + Raises a 404 if no valid week specification can be found. + + +DateMixin +~~~~~~~~~ +.. class:: DateMixin() + +A mixin class providing common behavior for all date-based views. + +**Attributes** + +.. attribute:: BaseDateListView.date_field + + The name of the ``DateField`` or ``DateTimeField`` in the + ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. + +.. attribute:: BaseDateListView.allow_future + + A boolean specifying whether to include "future" objects on this + page, where "future" means objects in which the field specified in + ``date_field`` is greater than the current date/time. By default, + this is ``False``. + +**Methods** + +.. method:: BaseDateListView.get_date_field() + + Returns the name of the field that contains the date data that + this view will operate on. Returns :attr:`DateMixin.date_field` by + default. + +.. method:: BaseDateListView.get_allow_future() + + Determine whether to include "future" objects on this page, where + "future" means objects in which the field specified in + ``date_field`` is greater than the current date/time. Returns + :attr:`DateMixin.date_field` by default. + +BaseDateListView +~~~~~~~~~~~~~~~~ +.. class:: BaseDateListView() + +A base class that provides common behavior for all date-based views. +There won't normally be a reason to instantiate +:class:`~django.views.generic.dates.BaseDateListView`; instantiate one of +the subclasses instead. + +While this view (and it's subclasses) are executing, +``self.object_list`` will contain the list of objects that the view is +operating upon, and ``self.date_list`` will contain the list of dates +for which data is available. + +**Mixins** + + * :class:`~django.views.generic.dates.DateMixin` + * :class:`~django.views.generic.list.MultipleObjectMixin` + +**Attributes** + +.. attribute:: BaseDateListView.allow_empty + + A boolean specifying whether to display the page if no objects are + available. If this is ``False`` and no objects are available, the + view will raise a 404 instead of displaying an empty page. By + default, this is ``True``. + +**Methods** + +.. method:: ArchiveView.get_dated_items(): + + Returns a 3-tuple containing:: + + (date_list, latest, extra_context) + + ``date_list`` is the list of dates for which data is available. + ``object_list`` is the list of objects ``extra_context`` is a + dictionary of context data that will be added to any context data + provided by the + :class:`~django.db.views.generic.list.MultiplObjectMixin`. + +.. method:: BaseDateListView.get_dated_queryset(**lookup) + + Returns a queryset, filtered using the query arguments defined by + ``lookup``. Enforces any restrictions on the queryset, such as + ``allow_empty`` and ``allow_future``. + +.. method:: BaseDateListView.get_date_list(queryset, date_type) + + Returns the list of dates of type ``date_type`` for which + ``queryset`` contains entries. For example, ``get_date_list(qs, + 'year')`` will return the list of years for which ``qs`` has + entries. See :meth:``~django.db.models.QuerySet.dates()` for the + ways that the ``date_type`` argument can be used. + + +Generic views +============= + +Simple generic views +-------------------- + +.. currentmodule:: django.views.generic.base + +View +~~~~ +.. class:: View() + +The master class-based base view. All other generic class-based views +inherit from this base class. + +Each request served by a :class:`~django.views.generic.base.View` has +an independent state; therefore, it is safe to store state variables +on the instance (i.e., ``self.foo = 3`` is a thread-safe operation). + +A class-based view is deployed into a URL pattern using the +:meth:`~View.as_view()` classmethod:: + + urlpatterns = patterns('', + (r'^view/$', MyView.as_view(size=42)), + ) + +Any argument passed into :meth:`~View.as_view()` will be assigned onto +the instance that is used to service a request. Using the previous +example, this means that every request on ``MyView`` is able to +interrogate ``self.size``. + +.. admonition:: Thread safety with view arguments + + Arguments passed to a view are shared between every instance of a + view. This means that you shoudn't use a list, dictionary, or any + other variable object as an argument to a view. If you did, the + actions of one user visiting your view could have an effect on + subsequent users visiting the same view. + +**Methods** + +.. method:: View.dispatch(request, *args, **kwargs) + + The ``view`` part of the view -- the method that accepts a + ``request`` argument plus arguments, and returns a HTTP response. + + The default implementation will inspect the HTTP method and + attempt to delegate to a method that matches the HTTP method; a + ``GET`` will be delegated to :meth:`~View.get()`, a ``POST`` to + :meth:`~View.post()`, and so on. + + The default implementation also sets ``request``, ``args`` and + ``kwargs`` as instance variables, so any method on the view can + know the full details of the request that was made to invoke the + view. + +.. method:: View.http_method_not_allowed(request, *args, **kwargs) + + If the view was called with HTTP method it doesn't support, this + method is called instead. + + The default implementation returns ``HttpResponseNotAllowed`` + with list of allowed methods in plain text. + +TemplateView +~~~~~~~~~~~~ +.. class:: TemplateView() + +Renders a given template, passing it a ``{{ params }}`` template +variable, which is a dictionary of the parameters captured in the URL. + +**Mixins** + + * :class:`django.views.generic.base.TemplateResponseMixin` + +**Attributes** + +.. attribute:: TemplateView.template_name + + The full name of a template to use. + +**Methods** + +.. method:: TemplateView.get_context_data(**kwargs) + + Return a context data dictionary consisting of the contents of + ``kwargs`` stored in the context variable ``params``. + +**Context** + + * ``params``: The dictionary of keyword arguments captured from + the URL pattern that served the view. + +RedirectView +~~~~~~~~~~~~ +.. class:: RedirectView() + +Redirects to a given URL. + +The given URL may contain dictionary-style string formatting, which +will be interpolated against the parameters captured in the URL. +Because keyword interpolation is *always* done (even if no arguments +are passed in), any ``"%"`` characters in the URL must be written as +``"%%"`` so that Python will convert them to a single percent sign on +output. + +If the given URL is ``None``, Django will return an +``HttpResponseGone`` (410). + +**Mixins** + +None. + +**Attributes** + +.. attribute:: RedirectView.url + + The URL to redirect to, as a string. Or ``None`` to raise a 410 + (Gone) HTTP error. + +.. attribute:: RedirectView.permanent + + Whether the redirect should be permanent. The only difference here + is the HTTP status code returned. If ``True``, then the redirect + will use status code 301. If ``False``, then the redirect will use + status code 302. By default, ``permanent`` is ``True``. + +.. attribute:: RedirectView.query_string + + Whether to pass along the GET query string to the new location. If + ``True``, then the query string is appended to the URL. If + ``False``, then the query string is discarded. By default, + ``query_string`` is ``False``. + +**Methods** + +.. method:: RedirectView.get_redirect_url(**kwargs) + + Constructs the target URL for redirection. + + The default implementation uses :attr:`~RedirectView.url` as a + starting string, performs expansion of ``%`` parameters in that + string, as well as the appending of query string if requested by + :attr:`~RedirectView.query_string`. Subclasses may implement any + behavior they wish, as long as the method returns a redirect-ready + URL string. + +Detail views +------------ + +.. currentmodule:: django.views.generic.detail + +DetailView +~~~~~~~~~~ +.. class:: BaseDetailView() +.. class:: DetailView() + +A page representing an individual object. + +While this view is executing, ``self.object`` will contain the object that +the view is operating upon. + +:class:`~django.views.generic.base.BaseDetailView` implements the same +behavior as :class:`~django.views.generic.base.DetailView`, but doesn't +include the +:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.detail.SingleObjectMixin` + * :class:`django.views.generic.detail.SingleObjectTemplateResponseMixin` + +List views +---------- + +.. currentmodule:: django.views.generic.list + +ListView +~~~~~~~~ +.. class:: BaseListView() +.. class:: ListView() + +A page representing a list of objects. + +While this view is executing, ``self.object_list`` will contain the +list of objects (usually, but not necessarily a queryset) that the +view is operating upon. + +:class:`~django.views.generic.list.BaseListView` implements the same +behavior as :class:`~django.views.generic.list.ListView`, but doesn't +include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.base.MultipleObjectMixin` + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + + +Editing views +------------- + +.. currentmodule:: django.views.generic.edit + +FormView +~~~~~~~~ +.. class:: BaseFormView() +.. class:: FormView() + +A view that displays a form. On error, redisplays the form with +validation errors; on success, redirects to a new URL. + +:class:`~django.views.generic.edit.BaseFormView` implements the same +behavior as :class:`~django.views.generic.edit.FormView`, but doesn't +include the :class:`~django.views.generic.base.TemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.edit.FormMixin` + * :class:`django.views.generic.edit.ProcessFormView` + +CreateView +~~~~~~~~~~ +.. class:: BaseCreateView() +.. class:: CreateView() + +A view that displays a form for creating an object, redisplaying the +form with validation errors (if there are any) and saving the object. + +:class:`~django.views.generic.edit.BaseCreateView` implements the same +behavior as :class:`~django.views.generic.edit.CreateView`, but +doesn't include the +:class:`~django.views.generic.base.TemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.edit.ModelFormMixin` + * :class:`django.views.generic.edit.ProcessFormView` + +UpdateView +~~~~~~~~~~ +.. class:: BaseUpdateView() +.. class:: UpdateView() + +A view that displays a form for editing an existing object, +redisplaying the form with validation errors (if there are any) and +saving changes to the object. This uses a form automatically generated +from the object's model class (unless a form class is manually +specified). + +:class:`~django.views.generic.edit.BaseUpdateView` implements the same +behavior as :class:`~django.views.generic.edit.UpdateView`, but +doesn't include the +:class:`~django.views.generic.base.TemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.edit.ModelFormMixin` + * :class:`django.views.generic.edit.ProcessFormView` + +DeleteView +~~~~~~~~~~ +.. class:: BaseDeleteView() +.. class:: DeleteView() + +A view that displays a confirmation page and deletes an existing object. The +given object will only be deleted if the request method is ``POST``. If this +view is fetched via ``GET``, it will display a confirmation page that should +contain a form that POSTs to the same URL. + +:class:`~django.views.generic.edit.BaseDeleteView` implements the same +behavior as :class:`~django.views.generic.edit.DeleteView`, but +doesn't include the +:class:`~django.views.generic.base.TemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.edit.ModelFormMixin` + * :class:`django.views.generic.edit.ProcessFormView` + +**Notes** + + * The delete confirmation page displayed to a GET request uses a + ``template_name_suffix`` of ``'_confirm_delete'``. + +Date-based views +---------------- + +Date-based generic views (in the module :mod:`django.views.generic.dates`) +are views for displaying drilldown pages for date-based data. + +.. currentmodule:: django.views.generic.dates + +ArchiveIndexView +~~~~~~~~~~~~~~~~ +.. class:: BaseArchiveIndexView() +.. class:: ArchiveIndexView() + +A top-level index page showing the "latest" objects, by date. Objects +with a date in the *future* are not included unless you set +``allow_future`` to ``True``. + +:class:`~django.views.generic.dates.BaseArchiveIndexView` implements +the same behavior as +:class:`~django.views.generic.dates.ArchiveIndexView`, but doesn't +include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.dates.BaseDateListView` + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + +**Notes** + + * Uses a default ``context_object_name`` of ``latest``. + + * Uses a default ``template_name_suffix`` of ``_archive``. + +YearArchiveView +~~~~~~~~~~~~~~~ +.. class:: BaseYearArchiveView() +.. class:: YearArchiveView() + +A yearly archive page showing all available months in a given year. +Objects with a date in the *future* are not displayed unless you set +``allow_future`` to ``True``. + +:class:`~django.views.generic.dates.BaseYearArchiveView` implements the +same behavior as :class:`~django.views.generic.dates.YearArchiveView`, +but doesn't include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + * :class:`django.views.generic.dates.YearMixin` + * :class:`django.views.generic.dates.BaseDateListView` + +**Attributes** + +.. attribute:: YearArchiveView.make_object_list + + A boolean specifying whether to retrieve the full list of objects + for this year and pass those to the template. If ``True``, the + list of objects will be made available to the context. By default, + this is ``False``. + +**Methods** + +.. method:: YearArchiveView.get_make_object_list() + + Determine if an object list will be returned as part of the context. + If ``False``, the ``None`` queryset will be used as the object list. + +**Context** + +In addition to the context provided by +:class:`django.views.generic.list.MultipleObjectMixin` (via +:class:`django.views.generic.dates.BaseDateListView`), the template's +context will be: + + * ``date_list``: A ``DateQuerySet`` object containing all months that have + have objects available according to ``queryset``, represented as + ``datetime.datetime`` objects, in ascending order. + + * ``year``: The given year, as a four-character string. + +**Notes** + + * Uses a default ``template_name_suffix`` of ``_archive_year``. + +MonthArchiveView +~~~~~~~~~~~~~~~~ +.. class:: BaseMonthArchiveView() +.. class:: MonthArchiveView() + +A monthly archive page showing all objects in a given month. Objects with a +date in the *future* are not displayed unless you set ``allow_future`` to +``True``. + +:class:`~django.views.generic.dates.BaseMonthArchiveView` implements +the same behavior as +:class:`~django.views.generic.dates.MonthArchiveView`, but doesn't +include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + * :class:`django.views.generic.dates.YearMixin` + * :class:`django.views.generic.dates.MonthMixin` + * :class:`django.views.generic.dates.BaseDateListView` + +**Attributes** + +**Methods** + +**Context** + +In addition to the context provided by +:class:`~django.views.generic.list.MultipleObjectMixin` (via +:class:`~django.views.generic.dates.BaseDateListView`), the template's +context will be: + + * ``date_list``: A ``DateQuerySet`` object containing all days that have + have objects available in the given month, according to ``queryset``, + represented as ``datetime.datetime`` objects, in ascending order. + + * ``month``: A ``datetime.date`` object representing the given month. + + * ``next_month``: A ``datetime.date`` object representing the first day of + the next month. If the next month is in the future, this will be + ``None``. + + * ``previous_month``: A ``datetime.date`` object representing the first day + of the previous month. Unlike ``next_month``, this will never be + ``None``. + +**Notes** + + * Uses a default ``template_name_suffix`` of ``_archive_month``. + +WeekArchiveView +~~~~~~~~~~~~~~~ +.. class:: BaseWeekArchiveView() +.. class:: WeekArchiveView() + +A weekly archive page showing all objects in a given week. Objects with a date +in the *future* are not displayed unless you set ``allow_future`` to ``True``. + +:class:`~django.views.generic.dates.BaseWeekArchiveView` implements the +same behavior as :class:`~django.views.generic.dates.WeekArchiveView`, +but doesn't include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + * :class:`django.views.generic.dates.YearMixin` + * :class:`django.views.generic.dates.MonthMixin` + * :class:`django.views.generic.dates.BaseDateListView` + +**Context** + +In addition to the context provided by +:class:`~django.views.generic.list.MultipleObjectMixin` (via +:class:`~django.views.generic.dates.BaseDateListView`), the template's +context will be: + + * ``week``: A ``datetime.date`` object representing the first day of the + given week. + +**Notes** + + * Uses a default ``template_name_suffix`` of ``_archive_week``. + +DayArchiveView +~~~~~~~~~~~~~~ +.. class:: BaseDayArchiveView() +.. class:: DayArchiveView() + +A day archive page showing all objects in a given day. Days in the future throw +a 404 error, regardless of whether any objects exist for future days, unless +you set ``allow_future`` to ``True``. + +:class:`~django.views.generic.dates.BaseDayArchiveView` implements the +same behavior as :class:`~django.views.generic.dates.DayArchiveView`, +but doesn't include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + * :class:`django.views.generic.dates.YearMixin` + * :class:`django.views.generic.dates.MonthMixin` + * :class:`django.views.generic.dates.DayMixin` + * :class:`django.views.generic.dates.BaseDateListView` + +**Context** + +In addition to the context provided by +:class:`~django.views.generic.list.MultipleObjectMixin` (via +:class:`~django.views.generic.dates.BaseDateListView`), the template's +context will be: + + * ``day``: A ``datetime.date`` object representing the given day. + + * ``next_day``: A ``datetime.date`` object representing the next day. If + the next day is in the future, this will be ``None``. + + * ``previous_day``: A ``datetime.date`` object representing the previous day. + Unlike ``next_day``, this will never be ``None``. + + * ``next_month``: A ``datetime.date`` object representing the first day of + the next month. If the next month is in the future, this will be + ``None``. + + * ``previous_month``: A ``datetime.date`` object representing the first day + of the previous month. Unlike ``next_month``, this will never be + ``None``. + +**Notes** + + * Uses a default ``template_name_suffix`` of ``_archive_day``. + +TodayArchiveView +~~~~~~~~~~~~~~~~ +.. class:: BaseTodayArchiveView() +.. class:: TodayArchiveView() + +A day archive page showing all objects for *today*. This is exactly the same as +``archive_day``, except the ``year``/``month``/``day`` arguments are not used, + +:class:`~django.views.generic.dates.BaseTodayArchiveView` implements +the same behavior as +:class:`~django.views.generic.dates.TodayArchiveView`, but doesn't +include the +:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.dates.DayArchiveView` + +DateDetailView +~~~~~~~~~~~~~~ +.. class:: BaseDateDetailView() +.. class:: DateDetailView() + +A page representing an individual object. If the object has a date value in the +future, the view will throw a 404 error by default, unless you set +``allow_future`` to ``True``. + +:class:`~django.views.generic.dates.BaseDateDetailView` implements the +same behavior as :class:`~django.views.generic.dates.DateDetailView`, +but doesn't include the +:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`. + +**Mixins** + + * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` + * :class:`django.views.generic.dates.YearMixin` + * :class:`django.views.generic.dates.MonthMixin` + * :class:`django.views.generic.dates.DayMixin` + * :class:`django.views.generic.dates.BaseDateListView` diff --git a/docs/ref/generic-views.txt b/docs/ref/generic-views.txt index 64d0d68739..c09cbca164 100644 --- a/docs/ref/generic-views.txt +++ b/docs/ref/generic-views.txt @@ -8,7 +8,7 @@ abstracted into "generic views" that let you quickly provide common views of an object without actually needing to write any Python code. A general introduction to generic views can be found in the :doc:`topic guide -</topics/http/generic-views>`. +</topics/generic-views>`. This reference contains details of Django's built-in generic views, along with a list of all keyword arguments that a generic view expects. Remember that diff --git a/docs/ref/index.txt b/docs/ref/index.txt index 09194178af..7b59589e74 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -12,7 +12,7 @@ API Reference exceptions files/index forms/index - generic-views + class-based-views middleware models/index request-response @@ -22,3 +22,11 @@ API Reference unicode utils validators + +Deprecated features +------------------- + +.. toctree:: + :maxdepth: 1 + + generic-views diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt index d681c4dbd3..8f722f6cbc 100644 --- a/docs/releases/1.3.txt +++ b/docs/releases/1.3.txt @@ -17,6 +17,23 @@ upgrade path from Django 1.2. What's new in Django 1.3 ======================== +Class-based views +~~~~~~~~~~~~~~~~~ + +Django 1.3 adds a framework that allows you to use a class as a view. +This means you can compose a view out of a collection of methods that +can be subclassed and overridden to provide + +Analogs of all the old function-based generic views have been +provided, along with a completely generic view base class that can be +used as the basis for reusable applications that can be easily +extended. + +See :doc:`the documentation on Generic Views</topics/generic-views>` +for more details. There is also a document to help you :doc:`convert +your function-based generic views to class-based +views</topics/generic-views-migration>`. + Logging ~~~~~~~ @@ -174,6 +191,18 @@ If you are currently using the ``mod_python`` request handler, it is strongly encouraged you redeploy your Django instances using :doc:`mod_wsgi </howto/deployment/modwsgi>`. +Function-based generic views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As a result of the introduction of class-based generic views, the +function-based generic views provided by Django have been deprecated. +The following modules and the views they contain have been deprecated: + + * :mod:`django.views.generic.create_update` + * :mod:`django.views.generic.date_based` + * :mod:`django.views.generic.list_detail` + * :mod:`django.views.generic.simple` + Test client response ``template`` attribute ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/class-based-views.txt b/docs/topics/class-based-views.txt new file mode 100644 index 0000000000..1f5421ab25 --- /dev/null +++ b/docs/topics/class-based-views.txt @@ -0,0 +1,535 @@ +========================= +Class-based generic views +========================= + +.. versionadded:: 1.3 + +.. note:: + Prior to Django 1.3, generic views were implemented as functions. The + function-based implementation has been deprecated in favor of the + class-based approach described here. + + For the reference to the old on details on the old implementation, + see the :doc:`topic guide </topics/generic-views>` and + :doc:`detailed reference </topics/generic-views>`. + +Writing Web applications can be monotonous, because we repeat certain patterns +again and again. Django tries to take away some of that monotony at the model +and template layers, but Web developers also experience this boredom at the view +level. + +Django's *generic views* were developed to ease that pain. They take certain +common idioms and patterns found in view development and abstract them so that +you can quickly write common views of data without having to write too much +code. + +We can recognize certain common tasks, like displaying a list of objects, and +write code that displays a list of *any* object. Then the model in question can +be passed as an extra argument to the URLconf. + +Django ships with generic views to do the following: + + * Perform common "simple" tasks: redirect to a different page and + render a given template. + + * Display list and detail pages for a single object. If we were creating an + application to manage conferences then a ``TalkListView`` and a + ``RegisteredUserListView`` would be examples of list views. A single + talk page is an example of what we call a "detail" view. + + * Present date-based objects in year/month/day archive pages, + associated detail, and "latest" pages. The Django Weblog's + (http://www.djangoproject.com/weblog/) year, month, and + day archives are built with these, as would be a typical + newspaper's archives. + + * Allow users to create, update, and delete objects -- with or + without authorization. + +Taken together, these views provide easy interfaces to perform the most common +tasks developers encounter. + + +Simple usage +============ + +Class-based generic views (and indeed any class-based views that are +based on 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, ``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 entrypoint for class-based views:: + + # urls.py + from django.conf.urls.defaults import * + 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.defaults import * + 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`, another simple +generic view. + + +Generic views of objects +======================== + +:class:`~django.views.generic.base.TemplateView` certainly is useful, +but Django's generic views really shine when it comes to presenting +views on your database content. Because it's such a common task, +Django comes with a handful of built-in generic views that make +generating list and detail views of objects incredibly easy. + +Let's take a look at one of these generic views: the "object list" view. We'll +be using these models:: + + # models.py + from django.db import models + + class Publisher(models.Model): + name = models.CharField(max_length=30) + address = models.CharField(max_length=50) + city = models.CharField(max_length=60) + state_province = models.CharField(max_length=30) + country = models.CharField(max_length=50) + website = models.URLField() + + def __unicode__(self): + return self.name + + class Meta: + ordering = ["-name"] + + class Book(models.Model): + title = models.CharField(max_length=100) + authors = models.ManyToManyField('Author') + publisher = models.ForeignKey(Publisher) + publication_date = models.DateField() + +To build a list page of all publishers, we'd use a URLconf along these lines:: + + from django.conf.urls.defaults import * + from django.views.generic import ListView + from books.models import Publisher + + urlpatterns = patterns('', + (r'^publishers/$', ListView.as_view( + model=Publisher, + )), + ) + +That's all the Python code we need to write. We still need to write a template, +however. We could explicitly tell the view which template to use +by including a ``template_name`` key in the arguments to as_view, but in +the absence of an explicit template Django will infer one from the object's +name. In this case, the inferred template will be +``"books/publisher_list.html"`` -- the "books" part comes from the name of the +app that defines the model, while the "publisher" bit is just the lowercased +version of the model's name. + +.. highlightlang:: html+django + +This template will be rendered against a context containing a variable called +``object_list`` that contains all the publisher objects. A very simple template +might look like the following:: + + {% extends "base.html" %} + + {% block content %} + <h2>Publishers</h2> + <ul> + {% for publisher in object_list %} + <li>{{ publisher.name }}</li> + {% endfor %} + </ul> + {% endblock %} + +That's really all there is to it. All the cool features of generic views come +from changing the "info" dictionary passed to the generic view. The +:doc:`generic views reference</ref/class-based-views>` documents all the generic +views and all their options in detail; the rest of this document will consider +some of the common ways you might customize and extend generic views. + + +Extending generic views +======================= + +.. highlightlang:: python + +There's no question that using generic views can speed up development +substantially. In most projects, however, there comes a moment when the +generic views no longer suffice. Indeed, the most common question asked by new +Django developers is how to make generic views handle a wider array of +situations. + +This is one of the reasons generic views were redesigned for the 1.3 release - +previously, they were just view functions with a bewildering array of options; +now, rather than passing in a large amount of configuration in the URLconf, +the recommended way to extend generic views is to subclass them, and override +their attributes or methods. + + +Making "friendly" template contexts +----------------------------------- + +You might have noticed that our sample publisher list template stores all the +books in a variable named ``object_list``. While this works just fine, it isn't +all that "friendly" to template authors: they have to "just know" that they're +dealing with publishers here. A better name for that variable would be +``publisher_list``; that variable's content is pretty obvious. + +We can change the name of that variable easily with the ``context_object_name`` +attribute - here, we'll override it in the URLconf, since it's a simple change: + +.. parsed-literal:: + + urlpatterns = patterns('', + (r'^publishers/$', ListView.as_view( + model=Publisher, + **context_object_name = "publisher_list",** + )), + ) + +Providing a useful ``context_object_name`` is always a good idea. Your +coworkers who design templates will thank you. + + +Adding extra context +-------------------- + +Often you simply need to present some extra information beyond that +provided by the generic view. For example, think of showing a list of +all the books on each publisher detail page. The +:class:`~django.views.generic.detail.DetailView` generic view provides +the publisher to the context, but it seems there's no way to get +additional information in that template. + +However, there is; you can subclass +:class:`~django.views.generic.detail.DetailView` and provide your own +implementation of the ``get_context_data`` method. The default +implementation of this that comes with +:class:`~django.views.generic.detail.DetailView` simply adds in the +object being displayed to the template, but we can override it to show +more:: + + from django.views.generic import DetailView + from some_app.models import Publisher, Book + + class PublisherDetailView(DetailView): + + context_object_name = "publisher" + model = Publisher + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = DetailView.get_context_data(self, **kwargs) + # Add in a QuerySet of all the books + context['book_list'] = Book.objects.all() + return context + + +Viewing subsets of objects +-------------------------- + +Now let's take a closer look at the ``model`` argument we've been +using all along. The ``model`` argument, which specifies the database +model that the view will operate upon, is available on all the +generic views that operate on a single object or a collection of +objects. However, the ``model`` argument is not the only way to +specify the objects that the view will operate upon -- you can also +specify the list of objects using the ``queryset`` argument:: + + from django.views.generic import DetailView + from some_app.models import Publisher, Book + + class PublisherDetailView(DetailView): + + context_object_name = "publisher" + queryset = Publisher.object.all() + +Specifying ``mode = Publisher`` is really just shorthand for saying +``queryset = Publisher.objects.all()``. However, by using ``queryset`` +to define a filtered list of objects you can be more specific about the +objects that will be visible in the view (see :doc:`/topics/db/queries` +for more information about ``QuerySet`` objects, and see the +:doc:`generic views reference</ref/generic-views>` for the complete details). + +To pick a simple example, we might want to order a list of books by +publication date, with the most recent first:: + + urlpatterns = patterns('', + (r'^publishers/$', ListView.as_view( + queryset = Publisher.objects.all(), + context_object_name = "publisher_list", + )), + (r'^publishers/$', ListView.as_view( + queryset = Book.objects.order_by("-publication_date"), + context_object_name = "book_list", + )), + ) + + +That's a pretty simple example, but it illustrates the idea nicely. Of course, +you'll usually want to do more than just reorder objects. If you want to +present a list of books by a particular publisher, you can use the same +technique (here, illustrated using subclassing rather than by passing arguments +in the URLconf):: + + from django.views.generic import ListView + from some_app.models import Book + + class AcmeBookListView(ListView): + + context_object_name = "book_list" + queryset = Book.objects.filter(publisher__name="Acme Publishing") + template_name = "books/acme_list.html" + +Notice that along with a filtered ``queryset``, we're also using a custom +template name. If we didn't, the generic view would use the same template as the +"vanilla" object list, which might not be what we want. + +Also notice that this isn't a very elegant way of doing publisher-specific +books. If we want to add another publisher page, we'd need another handful of +lines in the URLconf, and more than a few publishers would get unreasonable. +We'll deal with this problem in the next section. + +.. note:: + + If you get a 404 when requesting ``/books/acme/``, check to ensure you + actually have a Publisher with the name 'ACME Publishing'. Generic + views have an ``allow_empty`` parameter for this case. See the + :doc:`generic views reference</ref/class-based-views>` for more details. + + +Dynamic filtering +----------------- + +Another common need is to filter down the objects given in a list page by some +key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but +what if we wanted to write a view that displayed all the books by some arbitrary +publisher? + +Handily, the ListView has a ``get_queryset`` method we can override. Previously, +it has just been returning the value of the ``queryset`` attribute, but now we +can add more logic. + +The key part to making this work is that when class-based views are called, +various useful things are stored on ``self``; as well as the request +(``self.request``) this includes the positional (``self.args``) and name-based +(``self.kwargs``) arguments captured according to the URLconf. + +Here, we have a URLconf with a single captured group:: + + from some_app.views import PublisherBookListView + + urlpatterns = patterns('', + (r'^books/(\w+)/$', PublisherBookListView.as_view()), + ) + +Next, we'll write the ``PublisherBookListView`` view itself:: + + from django.shortcuts import get_object_or_404 + from django.views.generic import ListView + from some_app.models import Book, Publisher + + class PublisherBookListView(ListView): + + context_object_name = "book_list" + template_name = "books/books_by_publisher.html", + + def get_queryset(self): + publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) + return Book.objects.filter(publisher=publisher) + +As you can see, it's quite easy to add more logic to the queryset selection; +if we wanted, we could use ``self.request.user`` to filter using the current +user, or other more complex logic. + +We can also add the publisher into the context at the same time, so we can +use it in the template:: + + class PublisherBookListView(ListView): + + context_object_name = "book_list" + template_name = "books/books_by_publisher.html", + + def get_queryset(self): + self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) + return Book.objects.filter(publisher=self.publisher) + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = ListView.get_context_data(self, **kwargs) + # Add in the publisher + context['publisher'] = self.publisher + return context + +Performing extra work +--------------------- + +The last common pattern we'll look at involves doing some extra work before +or after calling the generic view. + +Imagine we had a ``last_accessed`` field on our ``Author`` object that we were +using to keep track of the last time anybody looked at that author:: + + # models.py + + class Author(models.Model): + salutation = models.CharField(max_length=10) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=40) + email = models.EmailField() + headshot = models.ImageField(upload_to='/tmp') + last_accessed = models.DateTimeField() + +The generic ``DetailView`` class, of course, wouldn't know anything about this +field, but once again we could easily write a custom view to keep that field +updated. + +First, we'd need to add an author detail bit in the URLconf to point to a +custom view: + +.. parsed-literal:: + + from some_app.views import AuthorDetailView + + urlpatterns = patterns('', + #... + **(r'^authors/(?P<pk>\\d+)/$', AuthorDetailView.as_view()),** + ) + +Then we'd write our new view - ``get_object`` is the method that retrieves the +object, so we simply override it and wrap the call:: + + import datetime + from some_app.models import Author + from django.views.generic import DetailView + from django.shortcuts import get_object_or_404 + + class AuthorDetailView(DetailView): + + queryset = Author.objects.all() + + def get_object(self, **kwargs): + # Call the superclass + object = DetailView.get_object(self, **kwargs) + # Record the lass accessed date + object.last_accessed = datetime.datetime.now() + object.save() + # Return the object + return object + +.. note:: + + This code won't actually work unless you create a + ``books/author_detail.html`` template. + +.. note:: + + The URLconf here uses the named group ``pk`` - this name is the default + name that DetailView uses to find the value of the primary key used to + filter the queryset. + + If you want to change it, you'll need to do your own ``get()`` call + on ``self.queryset`` using the new named parameter from ``self.kwargs``. + +More than just HTML +------------------- + +So far, we've been focusing on rendering templates to generate +responses. However, that's not all generic views can do. + +Each generic view is composed out of a series of mixins, and each +mixin contributes a little piece of the entire view. Some of these +mixins -- such as +:class:`~django.views.generic.base.TemplateResponseMixin` -- are +specifically designed for rendering content to a HTML response using a +template. However, you can write your own mixins that perform +different rendering behavior. + +For example, you a simple JSON mixin might look something like this:: + + class JSONResponseMixin(object): + def render_to_response(self, context): + "Returns a JSON response containing 'context' as payload" + return self.get_json_response(self.convert_context_to_json(context)) + + def get_json_response(self, content, **httpresponse_kwargs): + "Construct an `HttpResponse` object." + return http.HttpResponse(content, + content_type='application/json', + **httpresponse_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(content) + +Then, you could build a JSON-returning +:class:`~django.views.generic.detail.DetailView` by mixing your +: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 +:func:``render_to_response()`` implementation will override the +versions provided by :class:`JSONResponseMixin` and +:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`. diff --git a/docs/topics/generic-views-migration.txt b/docs/topics/generic-views-migration.txt new file mode 100644 index 0000000000..3ac4204413 --- /dev/null +++ b/docs/topics/generic-views-migration.txt @@ -0,0 +1,127 @@ +====================================== +Migrating function-based generic views +====================================== + +All the :doc:`function-based generic views</ref/generic-views>` +that existed in Django 1.2 have analogs as :doc:`class-based generic +views</ref/class-based-views>` in Django 1.3. The feature set +exposed in those function-based views can be replicated in a +class-based way. + +How to migrate +============== + +Replace generic views with generic classes +------------------------------------------ + +Existing usage of function-based generic views should be replaced with +their class-based analogs: + + ==================================================== ==================================================== + Old function-based generic view New class-based generic view + ==================================================== ==================================================== + ``django.views.generic.simple.direct_to_template`` :class:`django.views.generic.base.TemplateView` + ``django.views.generic.simple.redirect_to`` :class:`django.views.generic.base.RedirectView` + ``django.views.generic.list_detail.object_list`` :class:`django.views.generic.list.ListView` + ``django.views.generic.list_detail.object_detail`` :class:`django.views.generic.detail.DetailView` + ``django.views.generic.create_update.create_object`` :class:`django.views.generic.edit.CreateView` + ``django.views.generic.create_update.update_object`` :class:`django.views.generic.edit.UpdateView` + ``django.views.generic.create_update.delete_object`` :class:`django.views.generic.edit.DeleteView` + ``django.views.generic.date_based.archive_index`` :class:`django.views.generic.dates.ArchiveIndexView` + ``django.views.generic.date_based.archive_year`` :class:`django.views.generic.dates.YearArchiveView` + ``django.views.generic.date_based.archive_month`` :class:`django.views.generic.dates.MonthArchiveView` + ``django.views.generic.date_based.archive_week`` :class:`django.views.generic.dates.WeekArchiveView` + ``django.views.generic.date_based.archive_day`` :class:`django.views.generic.dates.DayArchiveView` + ``django.views.generic.date_based.archive_today`` :class:`django.views.generic.dates.TodayArchiveView` + ``django.views.generic.date_based.object_detail`` :class:`django.views.generic.dates.DateDetailView` + ==================================================== ==================================================== + +To do this, replace the reference to the generic view function with +a ``as_view()`` instantiation of the class-based view. For example, +the old-style ``direct_to_template`` pattern:: + + ('^about/$', direct_to_template, {'template': 'about.html'}) + +can be replaced with an instance of +:class:`~django.views.generic.base.TemplateView`:: + + ('^about/$', TemplateView.as_view(template_name='about.html')) + +``template`` argument to ``direct_to_template`` views +----------------------------------------------------- + +The ``template`` argument to the ``direct_to_template`` view has been renamed +``template_name``. This has ben done to maintain consistency with other views. + +``object_id`` argument to detail views +-------------------------------------- + +The object_id argument to the ``object_detail`` view has been renamed +``pk`` on the :class:`~django.views.generic.detail.DetailView`. + +``template_object_name`` +------------------------ + +``template_object_name`` has been renamed ``context_object_name``, +reflecting the fact that the context data can be used for purposes +other than template rendering (e.g., to populate JSON output). + +The ``_list`` suffix on list views +---------------------------------- + +In a function-based :class:`ListView`, the ``template_object_name`` +was appended with the suffix ``'_list'`` to yield the final context +variable name. In a class-based ``ListView``, the +``context_object_name`` is used verbatim. + +``extra_context`` +----------------- + +Function-based generic views provided an ``extra_context`` argument +as way to insert extra items into the context at time of rendering. + +Class-based views don't provide an ``extra_context`` argument. +Instead, you subclass the view, overriding :meth:`get_context_data()`. +For example:: + + class MyListView(ListView): + def get_context_data(self, **kwargs): + context = super(MyListView, self).get_context_data(**kwargs) + context.update({ + 'foo': 42, + 'bar': 37 + }) + return context + +``mimetype`` +------------ + +Some function-based generic views provided a ``mimetype`` argument +as way to control the mimetype of the response. + +Class-based views don't provide a ``mimetype`` argument. Instead, you +subclass the view, overriding +:meth:`TemplateResponseMixin.get_response()` and pass in arguments for +the HttpResponse constructor. For example:: + + class MyListView(ListView): + def get_response(self, content, **kwargs): + return super(MyListView, self).get_response(content, + content_type='application/json', **kwargs) + +``context_processors`` +---------------------- + +Some function-based generic views provided a ``context_processors`` +argument that could be used to force the use of specialized context +processors when rendering template content. + +Class-based views don't provide a ``context_processors`` argument. +Instead, you subclass the view, overriding +:meth:`TemplateResponseMixin.get_context_instance()`. For example:: + + class MyListView(ListView): + def get_context_instance(self, context): + return RequestContext(self.request, + context, + processors=[custom_processor]) diff --git a/docs/topics/index.txt b/docs/topics/index.txt index c9c2f2d033..1f680a1651 100644 --- a/docs/topics/index.txt +++ b/docs/topics/index.txt @@ -12,7 +12,8 @@ Introductions to all the key parts of Django you'll need to know: forms/index forms/modelforms templates - generic-views + class-based-views + generic-views-migration files testing auth @@ -26,3 +27,10 @@ Introductions to all the key parts of Django you'll need to know: settings signals +Deprecated features +------------------- + +.. toctree:: + :maxdepth: 1 + + generic-views |
