Fixed #19516 - Fixed remaining broken links.

Added -n to sphinx builds to catch issues going forward.
This commit is contained in:
Tim Graham 2013-01-01 08:12:42 -05:00
parent 3f890f8dc7
commit 9b5f64cc6e
83 changed files with 727 additions and 611 deletions

View file

@ -257,9 +257,9 @@ Specifying ``model = 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 :class:`QuerySet` objects, and see the
:doc:`class-based views reference </ref/class-based-views/index>` for the
complete details).
for more information about :class:`~django.db.models.query.QuerySet` objects,
and see the :doc:`class-based views reference </ref/class-based-views/index>`
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::
@ -312,9 +312,9 @@ what if we wanted to write a view that displayed all the books by some arbitrary
publisher?
Handily, the ``ListView`` has a
:meth:`~django.views.generic.detail.ListView.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.
:meth:`~django.views.generic.list.MultipleObjectMixin.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

View file

@ -7,10 +7,10 @@ Form processing generally has 3 paths:
* POST with invalid data (typically redisplay form with errors)
* POST with valid data (process the data and typically redirect)
Implementing this yourself often results in a lot of repeated
boilerplate code (see :ref:`Using a form in a
view<using-a-form-in-a-view>`). To help avoid this, Django provides a
collection of generic class-based views for form processing.
Implementing this yourself often results in a lot of repeated boilerplate code
(see :ref:`Using a form in a view<using-a-form-in-a-view>`). To help avoid
this, Django provides a collection of generic class-based views for form
processing.
Basic Forms
-----------
@ -28,7 +28,7 @@ Given a simple contact form::
# send email using the self.cleaned_data dictionary
pass
The view can be constructed using a FormView::
The view can be constructed using a ``FormView``::
# views.py
from myapp.forms import ContactForm
@ -50,42 +50,46 @@ Notes:
* FormView inherits
:class:`~django.views.generic.base.TemplateResponseMixin` so
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name`
can be used here
can be used here.
* The default implementation for
:meth:`~django.views.generic.edit.FormView.form_valid` simply
redirects to the :attr:`success_url`
:meth:`~django.views.generic.edit.FormMixin.form_valid` simply
redirects to the :attr:`~django.views.generic.edit.FormMixin.success_url`.
Model Forms
-----------
Generic views really shine when working with models. These generic
views will automatically create a :class:`ModelForm`, so long as they
can work out which model class to use:
views will automatically create a :class:`~django.forms.ModelForm`, so long as
they can work out which model class to use:
* If the :attr:`model` attribute is given, that model class will be used
* If :meth:`get_object()` returns an object, the class of that object
will be used
* If a :attr:`queryset` is given, the model for that queryset will be used
* If the :attr:`~django.views.generic.edit.ModelFormMixin.model` attribute is
given, that model class will be used.
* If :meth:`~django.views.generic.detail.SingleObjectMixin.get_object()`
returns an object, the class of that object will be used.
* If a :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` is
given, the model for that queryset will be used.
Model form views provide a :meth:`form_valid()` implementation that
saves the model automatically. You can override this if you have any
Model form views provide a
:meth:`~django.views.generic.edit.ModelFormMixin.form_valid()` implementation
that saves the model automatically. You can override this if you have any
special requirements; see below for examples.
You don't even need to provide a attr:`success_url` for
You don't even need to provide a ``success_url`` for
:class:`~django.views.generic.edit.CreateView` or
:class:`~django.views.generic.edit.UpdateView` - they will use
:meth:`get_absolute_url()` on the model object if available.
:meth:`~django.db.models.Model.get_absolute_url()` on the model object if available.
If you want to use a custom :class:`ModelForm` (for instance to add
extra validation) simply set
If you want to use a custom :class:`~django.forms.ModelForm` (for instance to
add extra validation) simply set
:attr:`~django.views.generic.edit.FormMixin.form_class` on your view.
.. note::
When specifying a custom form class, you must still specify the model,
even though the :attr:`form_class` may be a :class:`ModelForm`.
even though the :attr:`~django.views.generic.edit.FormMixin.form_class` may
be a :class:`~django.forms.ModelForm`.
First we need to add :meth:`get_absolute_url()` to our :class:`Author`
class:
First we need to add :meth:`~django.db.models.Model.get_absolute_url()` to our
``Author`` class:
.. code-block:: python
@ -137,8 +141,10 @@ Finally, we hook these new views into the URLconf::
.. note::
These views inherit :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
which uses :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_prefix`
These views inherit
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
which uses
:attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
to construct the
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name`
based on the model.
@ -149,15 +155,17 @@ Finally, we hook these new views into the URLconf::
* :class:`DeleteView` uses ``myapp/author_confirm_delete.html``
If you wish to have separate templates for :class:`CreateView` and
:class:1UpdateView`, you can set either :attr:`template_name` or
:attr:`template_name_suffix` on your view class.
:class:`UpdateView`, you can set either
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name` or
:attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
on your view class.
Models and request.user
-----------------------
To track the user that created an object using a :class:`CreateView`,
you can use a custom :class:`ModelForm` to do this. First, add the
foreign key relation to the model::
you can use a custom :class:`~django.forms.ModelForm` to do this. First, add
the foreign key relation to the model::
# models.py
from django.contrib.auth import User
@ -169,7 +177,7 @@ foreign key relation to the model::
# ...
Create a custom :class:`ModelForm` in order to exclude the
Create a custom :class:`~django.forms.ModelForm` in order to exclude the
``created_by`` field and prevent the user from editing it:
.. code-block:: python
@ -183,8 +191,10 @@ Create a custom :class:`ModelForm` in order to exclude the
model = Author
exclude = ('created_by',)
In the view, use the custom :attr:`form_class` and override
:meth:`form_valid()` to add the user::
In the view, use the custom
:attr:`~django.views.generic.edit.FormMixin.form_class` and override
:meth:`~django.views.generic.edit.ModelFormMixin.form_valid()` to add the
user::
# views.py
from django.views.generic.edit import CreateView
@ -202,7 +212,8 @@ In the view, use the custom :attr:`form_class` and override
Note that you'll need to :ref:`decorate this
view<decorating-class-based-views>` using
:func:`~django.contrib.auth.decorators.login_required`, or
alternatively handle unauthorised users in the :meth:`form_valid()`.
alternatively handle unauthorized users in the
:meth:`~django.views.generic.edit.ModelFormMixin.form_valid()`.
AJAX example
------------

View file

@ -32,13 +32,14 @@ Two central mixins are provided that help in providing a consistent
interface to working with templates in class-based views.
:class:`~django.views.generic.base.TemplateResponseMixin`
Every built in view which returns a
:class:`~django.template.response.TemplateResponse` will call the
:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
method that :class:`TemplateResponseMixin` provides. Most of the time this
method that ``TemplateResponseMixin`` provides. Most of the time this
will be called for you (for instance, it is called by the ``get()`` method
implemented by both :class:`~django.views.generic.base.TemplateView` and
:class:`~django.views.generic.base.DetailView`); similarly, it's unlikely
:class:`~django.views.generic.detail.DetailView`); similarly, it's unlikely
that you'll need to override it, although if you want your response to
return something not rendered via a Django template then you'll want to do
it. For an example of this, see the :ref:`JSONResponseMixin example
@ -59,10 +60,10 @@ interface to working with templates in class-based views.
:class:`~django.views.generic.base.ContextMixin`
Every built in view which needs context data, such as for rendering a
template (including :class:`TemplateResponseMixin` above), should call
template (including ``TemplateResponseMixin`` above), should call
:meth:`~django.views.generic.base.ContextMixin.get_context_data` passing
any data they want to ensure is in there as keyword arguments.
``get_context_data`` returns a dictionary; in :class:`ContextMixin` it
``get_context_data`` returns a dictionary; in ``ContextMixin`` it
simply returns its keyword arguments, but it is common to override this to
add more members to the dictionary.
@ -106,7 +107,7 @@ URLConf, and looks the object up either from the
:attr:`~django.views.generic.detail.SingleObjectMixin.model` attribute
on the view, or the
:attr:`~django.views.generic.detail.SingleObjectMixin.queryset`
attribute if that's provided). :class:`SingleObjectMixin` also overrides
attribute if that's provided). ``SingleObjectMixin`` also overrides
:meth:`~django.views.generic.base.ContextMixin.get_context_data`,
which is used across all Django's built in class-based views to supply
context data for template renders.
@ -115,10 +116,12 @@ To then make a :class:`~django.template.response.TemplateResponse`,
:class:`DetailView` uses
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
which extends :class:`~django.views.generic.base.TemplateResponseMixin`,
overriding :meth:`get_template_names()` as discussed above. It actually
provides a fairly sophisticated set of options, but the main one that most
people are going to use is ``<app_label>/<object_name>_detail.html``. The
``_detail`` part can be changed by setting
overriding
:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names()`
as discussed above. It actually provides a fairly sophisticated set of options,
but the main one that most people are going to use is
``<app_label>/<object_name>_detail.html``. The ``_detail`` part can be changed
by setting
:attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
on a subclass to something else. (For instance, the :doc:`generic edit
views<generic-editing>` use ``_form`` for create and update views, and
@ -128,9 +131,10 @@ ListView: working with many Django objects
------------------------------------------
Lists of objects follow roughly the same pattern: we need a (possibly
paginated) list of objects, typically a :class:`QuerySet`, and then we need
to make a :class:`TemplateResponse` with a suitable template using
that list of objects.
paginated) list of objects, typically a
:class:`~django.db.models.query.QuerySet`, and then we need to make a
:class:`~django.template.response.TemplateResponse` with a suitable template
using that list of objects.
To get the objects, :class:`~django.views.generic.list.ListView` uses
:class:`~django.views.generic.list.MultipleObjectMixin`, which
@ -138,9 +142,9 @@ provides both
:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`
and
:meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`. Unlike
with :class:`SingleObjectMixin`, there's no need to key off parts of
the URL to figure out the queryset to work with, so the default just
uses the
with :class:`~django.views.generic.detail.SingleObjectMixin`, there's no need
to key off parts of the URL to figure out the queryset to work with, so the
default just uses the
:attr:`~django.views.generic.list.MultipleObjectMixin.queryset` or
:attr:`~django.views.generic.list.MultipleObjectMixin.model` attribute
on the view class. A common reason to override
@ -148,19 +152,19 @@ on the view class. A common reason to override
here would be to dynamically vary the objects, such as depending on
the current user or to exclude posts in the future for a blog.
:class:`MultipleObjectMixin` also overrides
:class:`~django.views.generic.list.MultipleObjectMixin` also overrides
:meth:`~django.views.generic.base.ContextMixin.get_context_data` to
include appropriate context variables for pagination (providing
dummies if pagination is disabled). It relies on ``object_list`` being
passed in as a keyword argument, which :class:`ListView` arranges for
it.
To make a :class:`TemplateResponse`, :class:`ListView` then uses
To make a :class:`~django.template.response.TemplateResponse`,
:class:`ListView` then uses
:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`;
as with :class:`SingleObjectTemplateResponseMixin` above, this
overrides :meth:`get_template_names()` to provide :meth:`a range of
options
<~django.views.generic.list.MultipleObjectTempalteResponseMixin>`,
as with :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
above, this overrides ``get_template_names()`` to provide :meth:`a range of
options <django.views.generic.list.MultipleObjectTemplateResponseMixin>`,
with the most commonly-used being
``<app_label>/<object_name>_list.html``, with the ``_list`` part again
being taken from the
@ -197,13 +201,13 @@ the box.
If in doubt, it's often better to back off and base your work on
:class:`View` or :class:`TemplateView`, perhaps with
:class:`SimpleObjectMixin` and
:class:`MultipleObjectMixin`. Although you will probably end up
writing more code, it is more likely to be clearly understandable
to someone else coming to it later, and with fewer interactions to
worry about you will save yourself some thinking. (Of course, you
can always dip into Django's implementation of the generic class
based views for inspiration on how to tackle problems.)
:class:`~django.views.generic.detail.SingleObjectMixin` and
:class:`~django.views.generic.list.MultipleObjectMixin`. Although you
will probably end up writing more code, it is more likely to be clearly
understandable to someone else coming to it later, and with fewer
interactions to worry about you will save yourself some thinking. (Of
course, you can always dip into Django's implementation of the generic
class based views for inspiration on how to tackle problems.)
.. _method resolution order: http://www.python.org/download/releases/2.3/mro/
@ -247,9 +251,9 @@ We'll demonstrate this with the publisher modelling we used in the
In practice you'd probably want to record the interest in a key-value
store rather than in a relational database, so we've left that bit
out. The only bit of the view that needs to worry about using
:class:`SingleObjectMixin` is where we want to look up the author
we're interested in, which it just does with a simple call to
``self.get_object()``. Everything else is taken care of for us by the
:class:`~django.views.generic.detail.SingleObjectMixin` is where we want to
look up the author we're interested in, which it just does with a simple call
to ``self.get_object()``. Everything else is taken care of for us by the
mixin.
We can hook this into our URLs easily enough::
@ -265,7 +269,8 @@ We can hook this into our URLs easily enough::
Note the ``pk`` named group, which
:meth:`~django.views.generic.detail.SingleObjectMixin.get_object` uses
to look up the ``Author`` instance. You could also use a slug, or
any of the other features of :class:`SingleObjectMixin`.
any of the other features of
:class:`~django.views.generic.detail.SingleObjectMixin`.
Using SingleObjectMixin with ListView
-------------------------------------
@ -277,23 +282,24 @@ example, you might want to paginate through all the books by a
particular publisher.
One way to do this is to combine :class:`ListView` with
:class:`SingleObjectMixin`, so that the queryset for the paginated
list of books can hang off the publisher found as the single
:class:`~django.views.generic.detail.SingleObjectMixin`, so that the queryset
for the paginated list of books can hang off the publisher found as the single
object. In order to do this, we need to have two different querysets:
**Publisher queryset for use in get_object**
We'll set that up directly when we call :meth:`get_object()`.
We'll set that up directly when we call ``get_object()``.
**Book queryset for use by ListView**
We'll figure that out ourselves in :meth:`get_queryset()` so we
can take into account the Publisher we're looking at.
We'll figure that out ourselves in ``get_queryset()`` so we
can take into account the ``Publisher`` we're looking at.
.. note::
We have to think carefully about :meth:`get_context_data()`.
Since both :class:`SingleObjectMixin` and :class:`ListView` will
We have to think carefully about ``get_context_data()``.
Since both :class:`~django.views.generic.detail.SingleObjectMixin` and
:class:`ListView` will
put things in the context data under the value of
:attr:`context_object_name` if it's set, we'll instead explictly
``context_object_name`` if it's set, we'll instead explictly
ensure the Publisher is in the context data. :class:`ListView`
will add in the suitable ``page_obj`` and ``paginator`` for us
providing we remember to call ``super()``.
@ -316,13 +322,14 @@ Now we can write a new ``PublisherDetail``::
self.object = self.get_object(Publisher.objects.all())
return self.object.book_set.all()
Notice how we set ``self.object`` within :meth:`get_queryset` so we
can use it again later in :meth:`get_context_data`. If you don't set
:attr:`template_name`, the template will default to the normal
Notice how we set ``self.object`` within ``get_queryset()`` so we
can use it again later in ``get_context_data()``. If you don't set
``template_name``, the template will default to the normal
:class:`ListView` choice, which in this case would be
``"books/book_list.html"`` because it's a list of books;
:class:`ListView` knows nothing about :class:`SingleObjectMixin`, so
it doesn't have any clue this view is anything to do with a Publisher.
:class:`ListView` knows nothing about
:class:`~django.views.generic.detail.SingleObjectMixin`, so it doesn't have
any clue this view is anything to do with a Publisher.
.. highlightlang:: html+django
@ -365,7 +372,7 @@ Generally you can use
:class:`~django.views.generic.base.TemplateResponseMixin` and
:class:`~django.views.generic.detail.SingleObjectMixin` when you need
their functionality. As shown above, with a bit of care you can even
combine :class:`SingleObjectMixin` with
combine ``SingleObjectMixin`` with
:class:`~django.views.generic.list.ListView`. However things get
increasingly complex as you try to do so, and a good rule of thumb is:
@ -376,48 +383,48 @@ increasingly complex as you try to do so, and a good rule of thumb is:
list<generic-display>`, :doc:`editing<generic-editing>` and
date. For example it's fine to combine
:class:`TemplateView` (built in view) with
:class:`MultipleObjectMixin` (generic list), but you're likely to
have problems combining :class:`SingleObjectMixin` (generic
detail) with :class:`MultipleObjectMixin` (generic list).
:class:`~django.views.generic.list.MultipleObjectMixin` (generic list), but
you're likely to have problems combining ``SingleObjectMixin`` (generic
detail) with ``MultipleObjectMixin`` (generic list).
To show what happens when you try to get more sophisticated, we show
an example that sacrifices readability and maintainability when there
is a simpler solution. First, let's look at a naive attempt to combine
:class:`~django.views.generic.detail.DetailView` with
:class:`~django.views.generic.edit.FormMixin` to enable use to
``POST`` a Django :class:`Form` to the same URL as we're displaying an
object using :class:`DetailView`.
``POST`` a Django :class:`~django.forms.Form` to the same URL as we're
displaying an object using :class:`DetailView`.
Using FormMixin with DetailView
-------------------------------
Think back to our earlier example of using :class:`View` and
:class:`SingleObjectMixin` together. We were recording a user's
interest in a particular author; say now that we want to let them
leave a message saying why they like them. Again, let's assume we're
:class:`~django.views.generic.detail.SingleObjectMixin` together. We were
recording a user's interest in a particular author; say now that we want to
let them leave a message saying why they like them. Again, let's assume we're
not going to store this in a relational database but instead in
something more esoteric that we won't worry about here.
At this point it's natural to reach for a :class:`Form` to encapsulate
the information sent from the user's browser to Django. Say also that
we're heavily invested in `REST`_, so we want to use the same URL for
At this point it's natural to reach for a :class:`~django.forms.Form` to
encapsulate the information sent from the user's browser to Django. Say also
that we're heavily invested in `REST`_, so we want to use the same URL for
displaying the author as for capturing the message from the
user. Let's rewrite our ``AuthorDetailView`` to do that.
.. _REST: http://en.wikipedia.org/wiki/Representational_state_transfer
We'll keep the ``GET`` handling from :class:`DetailView`, although
we'll have to add a :class:`Form` into the context data so we can
we'll have to add a :class:`~django.forms.Form` into the context data so we can
render it in the template. We'll also want to pull in form processing
from :class:`~django.views.generic.edit.FormMixin`, and write a bit of
code so that on ``POST`` the form gets called appropriately.
.. note::
We use :class:`FormMixin` and implement :meth:`post()` ourselves
rather than try to mix :class:`DetailView` with :class:`FormView`
(which provides a suitable :meth:`post()` already) because both of
the views implement :meth:`get()`, and things would get much more
We use :class:`~django.views.generic.edit.FormMixin` and implement
``post()`` ourselves rather than try to mix :class:`DetailView` with
:class:`FormView` (which provides a suitable ``post()`` already) because
both of the views implement ``get()``, and things would get much more
confusing.
.. highlightlang:: python
@ -472,24 +479,24 @@ Our new ``AuthorDetail`` looks like this::
# record the interest using the message in form.cleaned_data
return super(AuthorDetail, self).form_valid(form)
:meth:`get_success_url()` is just providing somewhere to redirect to,
``get_success_url()`` is just providing somewhere to redirect to,
which gets used in the default implementation of
:meth:`form_valid()`. We have to provide our own :meth:`post()` as
noted earlier, and override :meth:`get_context_data()` to make the
:class:`Form` available in the context data.
``form_valid()``. We have to provide our own ``post()`` as
noted earlier, and override ``get_context_data()`` to make the
:class:`~django.forms.Form` available in the context data.
A better solution
-----------------
It should be obvious that the number of subtle interactions between
:class:`FormMixin` and :class:`DetailView` is already testing our
ability to manage things. It's unlikely you'd want to write this kind
of class yourself.
:class:`~django.views.generic.edit.FormMixin` and :class:`DetailView` is
already testing our ability to manage things. It's unlikely you'd want to
write this kind of class yourself.
In this case, it would be fairly easy to just write the :meth:`post()`
In this case, it would be fairly easy to just write the ``post()``
method yourself, keeping :class:`DetailView` as the only generic
functionality, although writing :class:`Form` handling code involves a
lot of duplication.
functionality, although writing :class:`~django.forms.Form` handling code
involves a lot of duplication.
Alternatively, it would still be easier than the above approach to
have a separate view for processing the form, which could use
@ -502,15 +509,15 @@ An alternative better solution
What we're really trying to do here is to use two different class
based views from the same URL. So why not do just that? We have a very
clear division here: ``GET`` requests should get the
:class:`DetailView` (with the :class:`Form` added to the context
:class:`DetailView` (with the :class:`~django.forms.Form` added to the context
data), and ``POST`` requests should get the :class:`FormView`. Let's
set up those views first.
The ``AuthorDisplay`` view is almost the same as :ref:`when we
first introduced AuthorDetail<generic-views-extra-work>`; we have to
write our own :meth:`get_context_data()` to make the
write our own ``get_context_data()`` to make the
``AuthorInterestForm`` available to the template. We'll skip the
:meth:`get_object()` override from before for clarity.
``get_object()`` override from before for clarity.
.. code-block:: python
@ -533,9 +540,9 @@ write our own :meth:`get_context_data()` to make the
return super(AuthorDisplay, self).get_context_data(**context)
Then the ``AuthorInterest`` is a simple :class:`FormView`, but we
have to bring in :class:`SingleObjectMixin` so we can find the author
we're talking about, and we have to remember to set
:attr:`template_name` to ensure that form errors will render the same
have to bring in :class:`~django.views.generic.detail.SingleObjectMixin` so we
can find the author we're talking about, and we have to remember to set
``template_name`` to ensure that form errors will render the same
template as ``AuthorDisplay`` is using on ``GET``.
.. code-block:: python
@ -568,14 +575,14 @@ template as ``AuthorDisplay`` is using on ``GET``.
return super(AuthorInterest, self).form_valid(form)
Finally we bring this together in a new ``AuthorDetail`` view. We
already know that calling :meth:`as_view()` on a class-based view
gives us something that behaves exactly like a function based view, so
we can do that at the point we choose between the two subviews.
already know that calling :meth:`~django.views.generic.base.View.as_view()` on
a class-based view gives us something that behaves exactly like a function
based view, so we can do that at the point we choose between the two subviews.
You can of course pass through keyword arguments to :meth:`as_view()`
in the same way you would in your URLconf, such as if you wanted the
``AuthorInterest`` behaviour to also appear at another URL but
using a different template.
You can of course pass through keyword arguments to
:meth:`~django.views.generic.base.View.as_view()` in the same way you
would in your URLconf, such as if you wanted the ``AuthorInterest`` behavior
to also appear at another URL but using a different template.
.. code-block:: python
@ -646,8 +653,8 @@ Now we mix this into the base TemplateView::
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
``JSONResponseMixin`` with the
``django.views.generic.detail.BaseDetailView`` -- (the
:class:`~django.views.generic.detail.DetailView` before template
rendering behavior has been mixed in)::
@ -662,11 +669,12 @@ 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
in both the ``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::
and override the implementation of
:func:`~django.views.generic.base.TemplateResponseMixin.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):
@ -678,5 +686,5 @@ requested::
Because of the way that Python resolves method overloading, the local
``render_to_response()`` implementation will override the versions provided by
:class:`JSONResponseMixin` and
``JSONResponseMixin`` and
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.