1
0
mirror of https://github.com/django/django.git synced 2025-10-24 06:06:09 +00:00

Fixed #30573 -- Rephrased documentation to avoid words that minimise the involved difficulty.

This patch does not remove all occurrences of the words in question.
Rather, I went through all of the occurrences of the words listed
below, and judged if they a) suggested the reader had some kind of
knowledge/experience, and b) if they added anything of value (including
tone of voice, etc). I left most of the words alone. I looked at the
following words:

- simply/simple
- easy/easier/easiest
- obvious
- just
- merely
- straightforward
- ridiculous

Thanks to Carlton Gibson for guidance on how to approach this issue, and
to Tim Bell for providing the idea. But the enormous lion's share of
thanks go to Adam Johnson for his patient and helpful review.
This commit is contained in:
Tobias Kunze
2019-06-17 16:54:55 +02:00
committed by Mariusz Felisiak
parent addabc492b
commit 4a954cfd11
149 changed files with 1101 additions and 1157 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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::

View File

@@ -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()`