diff options
Diffstat (limited to 'docs/topics/class-based-views')
| -rw-r--r-- | docs/topics/class-based-views/generic-display.txt | 69 | ||||
| -rw-r--r-- | docs/topics/class-based-views/generic-editing.txt | 10 | ||||
| -rw-r--r-- | docs/topics/class-based-views/index.txt | 50 | ||||
| -rw-r--r-- | docs/topics/class-based-views/intro.txt | 42 | ||||
| -rw-r--r-- | docs/topics/class-based-views/mixins.txt | 59 |
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()` |
