summaryrefslogtreecommitdiff
path: root/docs/topics/class-based-views
diff options
context:
space:
mode:
Diffstat (limited to 'docs/topics/class-based-views')
-rw-r--r--docs/topics/class-based-views/generic-display.txt69
-rw-r--r--docs/topics/class-based-views/generic-editing.txt10
-rw-r--r--docs/topics/class-based-views/index.txt50
-rw-r--r--docs/topics/class-based-views/intro.txt42
-rw-r--r--docs/topics/class-based-views/mixins.txt59
5 files changed, 112 insertions, 118 deletions
diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt
index 8e39ad6c14..ad5bb31b8e 100644
--- a/docs/topics/class-based-views/generic-display.txt
+++ b/docs/topics/class-based-views/generic-display.txt
@@ -29,8 +29,8 @@ Django ships with generic views to do the following:
* 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.
+Taken together, these views provide interfaces to perform the most common tasks
+developers encounter.
Extending generic views
@@ -43,10 +43,10 @@ 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.
+previously, they were 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.
That said, generic views will have a limit. If you find you're struggling to
implement your view as a subclass of a generic view, then you may find it more
@@ -63,8 +63,7 @@ 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 of 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.
+of built-in generic views to help generate list and detail views of objects.
Let's start by looking at some examples of showing a list of objects or an
individual object.
@@ -130,7 +129,7 @@ however. We could explicitly tell the view which template to use by adding a
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.
+bit is the lowercased version of the model's name.
.. note::
@@ -139,8 +138,8 @@ bit is just the lowercased version of the model's name.
be: /path/to/project/books/templates/books/publisher_list.html
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:
+``object_list`` that contains all the publisher objects. A template might look
+like the this:
.. code-block:: html+django
@@ -197,17 +196,16 @@ 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 how do we get additional information
-in that template?
+Often you 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 how do we get
+additional information in that template?
The answer is to subclass :class:`~django.views.generic.detail.DetailView`
and provide your own implementation of the ``get_context_data`` method.
-The default implementation simply adds the object being displayed to the
-template, but you can override it to send more::
+The default implementation adds the object being displayed to the template, but
+you can override it to send more::
from django.views.generic import DetailView
from books.models import Book, Publisher
@@ -261,16 +259,16 @@ specify the list of objects using the ``queryset`` argument::
context_object_name = 'publisher'
queryset = Publisher.objects.all()
-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:`~django.db.models.query.QuerySet` objects,
-and see the :doc:`class-based views reference </ref/class-based-views/index>`
-for the complete details).
+Specifying ``model = Publisher`` is 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:`~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::
+To pick an example, we might want to order a list of books by publication date,
+with the most recent first::
from django.views.generic import ListView
from books.models import Book
@@ -279,7 +277,7 @@ publication date, with the most recent first::
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,
+That's a pretty minimal 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::
@@ -321,8 +319,8 @@ publisher?
Handily, the ``ListView`` has a
: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.
+can override. By default, it returns the value of the ``queryset`` attribute,
+but we can use it to 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
@@ -354,9 +352,10 @@ Next, we'll write the ``PublisherBookList`` view itself::
self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])
return Book.objects.filter(publisher=self.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.
+Using ``get_queryset`` to add logic to the queryset selection is as convenient
+as it is powerful. For instance, 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::
@@ -407,7 +406,7 @@ custom 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::
+object -- so we override it and wrap the call::
from django.utils import timezone
from django.views.generic import DetailView
diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt
index 7124b146ac..c1e73fc2fb 100644
--- a/docs/topics/class-based-views/generic-editing.txt
+++ b/docs/topics/class-based-views/generic-editing.txt
@@ -16,7 +16,7 @@ processing.
Basic forms
===========
-Given a simple contact form:
+Given a contact form:
.. code-block:: python
:caption: forms.py
@@ -85,7 +85,7 @@ You don't even need to provide a ``success_url`` for
:meth:`~django.db.models.Model.get_absolute_url()` on the model object if available.
If you want to use a custom :class:`~django.forms.ModelForm` (for instance to
-add extra validation) simply set
+add extra validation), set
:attr:`~django.views.generic.edit.FormMixin.form_class` on your view.
.. note::
@@ -132,8 +132,8 @@ here; we don't have to write any logic ourselves:
success_url = reverse_lazy('author-list')
.. note::
- We have to use :func:`~django.urls.reverse_lazy` here, not just
- ``reverse()`` as the urls are not loaded when the file is imported.
+ We have to use :func:`~django.urls.reverse_lazy` instead of
+ ``reverse()``, as the urls are not loaded when the file is imported.
The ``fields`` attribute works the same way as the ``fields`` attribute on the
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
@@ -225,7 +225,7 @@ handle unauthorized users in :meth:`~.ModelFormMixin.form_valid()`.
AJAX example
============
-Here is a simple example showing how you might go about implementing a form that
+Here is an example showing how you might go about implementing a form that
works for AJAX requests as well as 'normal' form POSTs::
from django.http import JsonResponse
diff --git a/docs/topics/class-based-views/index.txt b/docs/topics/class-based-views/index.txt
index 17e8b66f8f..364746a093 100644
--- a/docs/topics/class-based-views/index.txt
+++ b/docs/topics/class-based-views/index.txt
@@ -6,10 +6,10 @@ A view is a callable which takes a request and returns a
response. This can be more than just a function, and Django provides
an example of some classes which can be used as views. These allow you
to structure your views and reuse code by harnessing inheritance and
-mixins. There are also some generic views for simple tasks which we'll
-get to later, but you may want to design your own structure of
-reusable views which suits your use case. For full details, see the
-:doc:`class-based views reference documentation</ref/class-based-views/index>`.
+mixins. There are also some generic views for tasks which we'll get to later,
+but you may want to design your own structure of reusable views which suits
+your use case. For full details, see the :doc:`class-based views reference
+documentation</ref/class-based-views/index>`.
.. toctree::
:maxdepth: 1
@@ -25,18 +25,18 @@ Basic examples
Django provides base view classes which will suit a wide range of applications.
All views inherit from the :class:`~django.views.generic.base.View` class, which
handles linking the view in to the URLs, HTTP method dispatching and other
-simple features. :class:`~django.views.generic.base.RedirectView` is for a
-simple HTTP redirect, and :class:`~django.views.generic.base.TemplateView`
-extends the base class to make it also render a template.
+common features. :class:`~django.views.generic.base.RedirectView` provides a
+HTTP redirect, and :class:`~django.views.generic.base.TemplateView` extends the
+base class to make it also render a template.
-Simple usage in your URLconf
-============================
+Usage in your URLconf
+=====================
-The simplest way to use generic views is to create them directly in your
-URLconf. If you're only changing a few simple attributes on a class-based view,
-you can simply pass them into the
-:meth:`~django.views.generic.base.View.as_view` method call itself::
+The most direct way to use generic views is to create them directly in your
+URLconf. If you're only changing a few attributes on a class-based view, you
+can pass them into the :meth:`~django.views.generic.base.View.as_view` method
+call itself::
from django.urls import path
from django.views.generic import TemplateView
@@ -59,8 +59,8 @@ existing view and override attributes (such as the ``template_name``) or
methods (such as ``get_context_data``) in your subclass to provide new values
or methods. Consider, for example, a view that just displays one template,
``about.html``. Django has a generic view to do this -
-:class:`~django.views.generic.base.TemplateView` - so we can just subclass it,
-and override the template name::
+:class:`~django.views.generic.base.TemplateView` - so we can subclass it, and
+override the template name::
# some_app/views.py
from django.views.generic import TemplateView
@@ -68,11 +68,10 @@ and override the template name::
class AboutView(TemplateView):
template_name = "about.html"
-Then we just need to add this new view into our URLconf.
-:class:`~django.views.generic.base.TemplateView` is a class, not a function,
-so we point the URL to the :meth:`~django.views.generic.base.View.as_view`
-class method instead, which provides a function-like entry to class-based
-views::
+Then we need to add this new view into our URLconf.
+:class:`~django.views.generic.base.TemplateView` is a class, not a function, so
+we point the URL to the :meth:`~django.views.generic.base.View.as_view` class
+method instead, which provides a function-like entry to class-based views::
# urls.py
from django.urls import path
@@ -123,9 +122,8 @@ And the view::
response['Last-Modified'] = last_book.publication_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
return response
-If the view is accessed from a ``GET`` request, a plain-and-simple object
-list is returned in the response (using ``book_list.html`` template). But if
-the client issues a ``HEAD`` request, the response has an empty body and
-the ``Last-Modified`` header indicates when the most recent book was published.
-Based on this information, the client may or may not download the full object
-list.
+If the view is accessed from a ``GET`` request, an object list is returned in
+the response (using the ``book_list.html`` template). But if the client issues
+a ``HEAD`` request, the response has an empty body and the ``Last-Modified``
+header indicates when the most recent book was published. Based on this
+information, the client may or may not download the full object list.
diff --git a/docs/topics/class-based-views/intro.txt b/docs/topics/class-based-views/intro.txt
index b1212af585..6b31180cf9 100644
--- a/docs/topics/class-based-views/intro.txt
+++ b/docs/topics/class-based-views/intro.txt
@@ -25,7 +25,7 @@ these patterns and ease view development for the common cases.
The problem with function-based generic views is that while they covered the
simple cases well, there was no way to extend or customize them beyond some
-simple configuration options, limiting their usefulness in many real-world
+configuration options, limiting their usefulness in many real-world
applications.
Class-based generic views were created with the same objective as
@@ -35,9 +35,9 @@ results in class-based generic views being more extensible and flexible than
their function-based counterparts.
If you have tried function based generic views in the past and found them
-lacking, you should not think of class-based generic views as simply a
-class-based equivalent, but rather as a fresh approach to solving the original
-problems that generic views were meant to solve.
+lacking, you should not think of class-based generic views as a class-based
+equivalent, but rather as a fresh approach to solving the original problems
+that generic views were meant to solve.
The toolkit of base classes and mixins that Django uses to build class-based
generic views are built for maximum flexibility, and as such have many hooks in
@@ -45,11 +45,11 @@ the form of default method implementations and attributes that you are unlikely
to be concerned with in the simplest use cases. For example, instead of
limiting you to a class-based attribute for ``form_class``, the implementation
uses a ``get_form`` method, which calls a ``get_form_class`` method, which in
-its default implementation just returns the ``form_class`` attribute of the
-class. This gives you several options for specifying what form to use, from a
-simple attribute, to a fully dynamic, callable hook. These options seem to add
-hollow complexity for simple situations, but without them, more advanced
-designs would be limited.
+its default implementation returns the ``form_class`` attribute of the class.
+This gives you several options for specifying what form to use, from an
+attribute, to a fully dynamic, callable hook. These options seem to add hollow
+complexity for simple situations, but without them, more advanced designs would
+be limited.
Using class-based views
=======================
@@ -221,7 +221,7 @@ A similar class-based view might look like::
return render(request, self.template_name, {'form': form})
-This is a very simple case, but you can see that you would then have the option
+This is a minimal case, but you can see that you would then have the option
of customizing this view by overriding any of the class attributes, e.g.
``form_class``, via URLconf configuration, or subclassing and overriding one or
more of the methods (or both!).
@@ -236,9 +236,9 @@ differently depending on if you're using ``as_view()`` or creating a subclass.
Decorating in URLconf
---------------------
-The simplest way of decorating class-based views is to decorate the
-result of the :meth:`~django.views.generic.base.View.as_view` method.
-The easiest place to do this is in the URLconf where you deploy your view::
+You can adjust class-based views by decorating the result of the
+:meth:`~django.views.generic.base.View.as_view` method. The easiest place to do
+this is in the URLconf where you deploy your view::
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
@@ -263,11 +263,11 @@ To decorate every instance of a class-based view, you need to decorate
the class definition itself. To do this you apply the decorator to the
:meth:`~django.views.generic.base.View.dispatch` method of the class.
-A method on a class isn't quite the same as a standalone function, so
-you can't just apply a function decorator to the method -- you need to
-transform it into a method decorator first. The ``method_decorator``
-decorator transforms a function decorator into a method decorator so
-that it can be used on an instance method. For example::
+A method on a class isn't quite the same as a standalone function, so you can't
+just apply a function decorator to the method -- you need to transform it into
+a method decorator first. The ``method_decorator`` decorator transforms a
+function decorator into a method decorator so that it can be used on an
+instance method. For example::
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
@@ -306,9 +306,9 @@ The decorators will process a request in the order they are passed to the
decorator. In the example, ``never_cache()`` will process the request before
``login_required()``.
-In this example, every instance of ``ProtectedView`` will have login protection.
-These examples use ``login_required``, however, the same behavior can be
-obtained more simply using
+In this example, every instance of ``ProtectedView`` will have login
+protection. These examples use ``login_required``, however, the same behavior
+can be obtained by using
:class:`~django.contrib.auth.mixins.LoginRequiredMixin`.
.. note::
diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt
index ad9fb7547b..fdc53e5c3b 100644
--- a/docs/topics/class-based-views/mixins.txt
+++ b/docs/topics/class-based-views/mixins.txt
@@ -46,7 +46,7 @@ interface to working with templates in class-based views.
``render_to_response()`` itself calls
:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`,
- which by default will just look up
+ which by default will look up
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name` on
the class-based view; two other mixins
(:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
@@ -61,8 +61,8 @@ interface to working with templates in class-based views.
: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 ``ContextMixin`` it
- simply returns its keyword arguments, but it is common to override this to
- add more members to the dictionary. You can also use the
+ returns its keyword arguments, but it is common to override this to add
+ more members to the dictionary. You can also use the
:attr:`~django.views.generic.base.ContextMixin.extra_context` attribute.
Building up Django's generic class-based views
@@ -142,7 +142,7 @@ and
:meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`. Unlike
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
+default 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
@@ -212,11 +212,10 @@ the box.
Using ``SingleObjectMixin`` with View
-------------------------------------
-If we want to write a simple class-based view that responds only to
-``POST``, we'll subclass :class:`~django.views.generic.base.View` and
-write a ``post()`` method in the subclass. However if we want our
-processing to work on a particular object, identified from the URL,
-we'll want the functionality provided by
+If we want to write a class-based view that responds only to ``POST``, we'll
+subclass :class:`~django.views.generic.base.View` and write a ``post()`` method
+in the subclass. However if we want our processing to work on a particular
+object, identified from the URL, we'll want the functionality provided by
:class:`~django.views.generic.detail.SingleObjectMixin`.
We'll demonstrate this with the ``Author`` model we used in the
@@ -249,9 +248,8 @@ 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:`~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.
+look up the author we're interested in, which it does with a 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:
@@ -288,8 +286,8 @@ object. In order to do this, we need to have two different querysets:
``Book`` queryset for use by :class:`~django.views.generic.list.ListView`
Since we have access to the ``Publisher`` whose books we want to list, we
- simply override ``get_queryset()`` and use the ``Publisher``’s
- :ref:`reverse foreign key manager<backwards-related-objects>`.
+ override ``get_queryset()`` and use the ``Publisher``’s :ref:`reverse
+ foreign key manager<backwards-related-objects>`.
``Publisher`` queryset for use in :meth:`~django.views.generic.detail.SingleObjectMixin.get_object()`
We'll rely on the default implementation of ``get_object()`` to fetch the
@@ -476,24 +474,23 @@ Our new ``AuthorDetail`` looks like this::
# passed in form.cleaned_data['message']
return super().form_valid(form)
-``get_success_url()`` is just providing somewhere to redirect to,
+``get_success_url()`` is provides somewhere to redirect to,
which gets used in the default implementation of
``form_valid()``. We have to provide our own ``post()`` as noted earlier.
A better solution
-----------------
-It should be obvious that the number of subtle interactions between
+The number of subtle interactions between
: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 ``post()``
-method yourself, keeping :class:`DetailView` as the only generic
-functionality, although writing :class:`~django.forms.Form` handling code
-involves a lot of duplication.
+In this case, you could write the ``post()`` method yourself, keeping
+:class:`DetailView` as the only generic 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
+Alternatively, it would still be less work than the above approach to
have a separate view for processing the form, which could use
:class:`~django.views.generic.edit.FormView` distinct from
:class:`DetailView` without concerns.
@@ -529,11 +526,11 @@ write our own ``get_context_data()`` to make the
context['form'] = AuthorInterestForm()
return context
-Then the ``AuthorInterest`` is a simple :class:`FormView`, but we
-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``::
+Then the ``AuthorInterest`` is a :class:`FormView`, but we 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``::
from django.http import HttpResponseForbidden
from django.urls import reverse
@@ -593,7 +590,7 @@ rendered HTML.
We can create a mixin class to use in all of our views, handling the
conversion to JSON once.
-For example, a simple JSON mixin might look something like this::
+For example, a JSON mixin might look something like this::
from django.http import JsonResponse
@@ -628,8 +625,8 @@ For example, a simple JSON mixin might look something like this::
This mixin provides a ``render_to_json_response()`` method with the same signature
as :func:`~django.views.generic.base.TemplateResponseMixin.render_to_response()`.
-To use it, we simply need to mix it into a ``TemplateView`` for example,
-and override ``render_to_response()`` to call ``render_to_json_response()`` instead::
+To use it, we need to mix it into a ``TemplateView`` for example, and override
+``render_to_response()`` to call ``render_to_json_response()`` instead::
from django.views.generic import TemplateView
@@ -657,8 +654,8 @@ 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 ``JSONResponseMixin`` and a
+the HTTP request, such as a query argument or a HTTP header. Mix in both the
+``JSONResponseMixin`` and a
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
and override the implementation of
:func:`~django.views.generic.base.TemplateResponseMixin.render_to_response()`