Django 1.8 official document translation: 3-4-2 class based built-in general view

Time:2021-9-20

Class based built-in general view

Writing web applications can be tedious because you need to repeat a pattern. Django tries to remove some monotony from the model and template layers, but web developers still experience this boredom in the view layer.

Django’s common view was developed to eliminate this pain. They adopt some common idioms and patterns found in the development process, and then abstract them so that you can write less code and quickly implement the basic view.

We can identify some basic tasks, such as displaying a list of objects and writing code to display a list of any object. In addition, the model in question can be passed to urlconf as an additional parameter.

Django accomplishes the following functions through a common view:

  • Display a list and a detail page for a single object. If we create an application to manage meetings, a talklistview (discussion list view) and a registered user listview (registered user list view) are examples of list views. A separate discussion information page is an example of what we call a “detailed” view.

  • The database based objects are displayed on the year / month / day archive page, as well as the details page and the “final publication” page.
    Allows users to create, update, and delete objects — with or without authorization.

In general, these views provide some simple interfaces to complete most common tasks encountered by developers.

Extended general view

There is no doubt that using a common view can greatly improve the development speed. However, in most projects, there are always times when the general view can not meet the requirements. Indeed, most of the problems from new Django developers are how to make common views more widely used.

This is one of the reasons why general views were redesigned in the 1.3 release – before, they were just some function views with a list of confusing options; Now, rather than passing a large number of configurations to urlconf, the more recommended way to extend the general view is to subclass them and override their properties or methods.

That is to say, the general view has some limitations. If you implement your view as a subclass of a generic view, you will find that it is more effective to write the code you want and use your own class or function based view.

In some third-party applications, there are more examples of common views, or you can write them on demand.

General view of objects

Templateview is really useful, but Django’s general view really stands out when you need to render the content in your database. Because this is such a common task, Django provides a large number of built-in general views, which makes it extremely easy to generate the display list and detailed view of objects.

Let’s look at the object list view among these common views.

We will use the following model:

# models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    class Meta:
        ordering = ["-name"]

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Author(models.Model):
    salutation = models.CharField(max_length=10)
    name = models.CharField(max_length=200)
    email = models.EmailField()
    headshot = models.ImageField(upload_to='author_headshots')

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField('Author')
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

Now we need to define a view:

# views.py
from django.views.generic import ListView
from books.models import Publisher

class PublisherList(ListView):
    model = Publisher

Finally, parse the view to your URL:

# urls.py
from django.conf.urls import url
from books.views import PublisherList

urlpatterns = [
    url(r'^publishers/$', PublisherList.as_view()),
]

The above is all the Python code we need to write.

be careful

Therefore, when (for example) djangotemplates is used as the back-end app_ When the dirs option is set to true in templates, the location of the template should be: / path / to / project / books / templates / books / publisher_ list.html。

The template will be rendered according to a context, which contains an object named object_ List contains variables for all publisher objects. A very simple template might look like this:

{% extends "base.html" %}

{% block content %}
    <h2>Publishers</h2>
    <ul>
        {% for publisher in object_list %}
            <li>{{ publisher.name }}</li>
        {% endfor %}
    </ul>
{% endblock %}

This is really all the code. The interesting feature in all general views comes from modifying the “information” dictionary passed to the general view. The generic views reference document details the general view and its options; The remainder of this document describes common methods for customizing and extending common views.

Write a “friendly” template context

You may have noticed that we put all publisher objects into object in the example of publisher list_ List variable. Although this works, it is not “friendly” to the template author. They just need to know how to deal with publishers here.

Therefore, if you are dealing with a model object, this is enough for you. When you process an object or queryset, Django can fill the context with the readme (verbose name, or plural readme for object list) you define for object display. Provides objects added to the default_ List entity, but contains exactly the same data, such as publisher_ list。

If the readme (or plural readme) still does not meet the requirements, you can manually set the name of the context variable. Context on a common view_ object_ The name attribute specifies the context variable to use:

# views.py
from django.views.generic import ListView
from books.models import Publisher

class PublisherList(ListView):
    model = Publisher
    context_object_name = 'my_favorite_publishers'

Provide a useful context_ object_ Name is always a good idea. Your colleagues who work with you in designing templates will thank you.

Add additional context

Most of the time, you just need to show some additional information rather than provide some general views. For example, consider the display of the book list on each publisher detail page. The detailview general view provides a publisher object to the context, but how do we add additional information to the template?

The answer is to derive the detailview, and in get_ context_ Provide your own implementation in the data method. The default implementation simply adds objects to be displayed to the template, but you can override this to display more information:

from django.views.generic import DetailView
from books.models import Publisher, Book

class PublisherDetail(DetailView):

    model = Publisher

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(PublisherDetail, self).get_context_data(**kwargs)
        # Add in a QuerySet of all the books
        context['book_list'] = Book.objects.all()
        return context

be careful

Usually, get_ context_ Data will merge the context data in the current class into the context data in all superclasses. To maintain this behavior in a class that you want to change the context, you should ensure that get_ is invoked in the superclass. context_ data。 If no two classes attempt to define the same key, an exception result is returned. However, if any class tries to override it when the superclass holds a key (after calling the superclass), any subclass of this class needs to set it explicitly after the superclass if you want to ensure that they override all superclasses. If you have this problem, review the method call order in your view.

View a subset of objects

Now let’s take a closer look at the model parameters we’ve been using. The model parameter specifies the database model on which the view operates, which is applicable to all general views that need to operate on a single object or a collection of objects. However, the model parameter is not the only way to indicate which object the view is based on — you can also use the queryset parameter to specify an object list:

from django.views.generic import DetailView
from books.models import Publisher

class PublisherDetail(DetailView):

    context_object_name = 'publisher'
    queryset = Publisher.objects.all()

Specifying model = publisher is equivalent to quick declared queryset = publisher. Objects. All(). However, by using queryset to define a filtered object list, you can know which objects will be displayed in the view in more detail (see executing query for more information about query set objects, and see class based View reference for full details).

We may want to sort the book list by publication date to select a simple example and put the most recent one first:

from django.views.generic import ListView
from books.models import Book

class BookList(ListView):
    queryset = Book.objects.order_by('-publication_date')
    context_object_name = 'book_list'

This is a very simple list, but it explains the processing idea very well. Of course, you usually want to do more than just sort the object list. If you want to present a list of all the books of a publisher, you can use the same method:

from django.views.generic import ListView
from books.models import Book

class AcmeBookList(ListView):

    context_object_name = 'book_list'
    queryset = Book.objects.filter(publisher__name='Acme Publishing')
    template_name = 'books/acme_list.html'

Note that in addition to the filtered query set, we also define our customized template name. If we don’t, we will use the same template as the “vanilla” object list name through the view, which may not be what we want.

Also note that this is not a very elegant way to deal with books from specific publishers. If we want to create another publisher page, we need to add a few more lines of code to urlconf, and a few more publishers will find it unreasonable to do so. We will deal with this in the next chapter.

be careful

If you have a 404 error accessing / books / acme /, check to make sure you do have a publisher named “Acme Publishing”. The generic view has an allow in this case_ Parameter of empty. See class based View reference for details.

Dynamic filtering

Another common requirement is to filter objects according to the keywords in the URL in a given list page. Previously, we hard coded the publisher’s name into urlconf, but what should we do if we want to write a view to show all the books of any publisher?

Quite conveniently, listview has a get_ Queryset () method for us to override. Previously, it only returned a queryset property value, but now we can add more logic.

The key to making this approach work is that when the class view is called, various useful objects are stored on self; Like request () (self. Request), it contains the location parameter (self. Args) and name based parameter (self. Kwargs) (keyword parameter) obtained from urlconf.

Here, we have a urlconf with a set of parameters for capture:

# urls.py
from django.conf.urls import url
from books.views import PublisherBookList

urlpatterns = [
    url(r'^books/([\w-]+)/$', PublisherBookList.as_view()),
]

Next, we wrote the publisherbooklist view:

# views.py
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher

class PublisherBookList(ListView):

    template_name = 'books/books_by_publisher.html'

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.args[0])
        return Book.objects.filter(publisher=self.publisher)

As you can see, it’s easy to add more logic in the queryset area; If we want, we can use self. Request. User to filter the current user, or add other more complex logic.

At the same time, we can add the publisher to the context so that we can use it in the template:

# ...

def get_context_data(self, **kwargs):
    # Call the base implementation first to get a context
    context = super(PublisherBookList, self).get_context_data(**kwargs)
    # Add in the publisher
    context['publisher'] = self.publisher
    return context

Perform additional work

The final common pattern we need to consider incurs additional overhead before or after invoking the common view.

Imagine that there is a last on our author object_ Accessed field, which is used to track when someone last viewed the author.

# models.py
from django.db import models

class Author(models.Model):
    salutation = models.CharField(max_length=10)
    name = models.CharField(max_length=200)
    email = models.EmailField()
    headshot = models.ImageField(upload_to='author_headshots')
    last_accessed = models.DateTimeField()

The general detailview class, of course, doesn’t know about this field, but we can easily write a custom view again to keep this field updated.

First, we need to add the code of the author details page to the urlconf and point to the customized view:

from django.conf.urls import url
from books.views import AuthorDetailView

urlpatterns = [
    #...
    url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetailView.as_view(), name='author-detail'),
]

Then, write our new view — get_ Object is the method used to get the object — so we simply rewrite it and encapsulate the call:

from django.views.generic import DetailView
from django.utils import timezone
from books.models import Author

class AuthorDetailView(DetailView):

    queryset = Author.objects.all()

    def get_object(self):
        # Call the superclass
        object = super(AuthorDetailView, self).get_object()
        # Record the last accessed date
        object.last_accessed = timezone.now()
        object.save()
        # Return the object
        return object

be careful

Here, urlconf uses the parameter group name PK – which is the default name used by detailview to find the value of the primary key, where the primary key is used to filter the query set.

If you want to call other methods of the parameter group, you can set PK on the view_ url_ kwarg。 See detailview reference for details.

translator:Flying dragon, Original:Built-in display views

In this paperCC BY-NC-SA 3.0Please keep the author’s signature and the source of the article.

Django document collaborative translation teamThere is a shortage of staff. Interested friends can join us. It is completely public welfare. Communication group: 467338606.

If you think the article is good, you can scan the QR code below to reward me.

Django 1.8 official document translation: 3-4-2 class based built-in general view

Recommended Today

Swift advanced (XV) extension

The extension in swift is somewhat similar to the category in OC Extension can beenumeration、structural morphology、class、agreementAdd new features□ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc What extensions can’t do:□ original functions cannot be overwritten□ you cannot add storage attributes or add attribute observers to existing attributes□ cannot add parent […]