Greetings to you again, dear readers! I publish another article from the cycle about Class Based Views (hereinafter CBV) in Django. This time I, as planned, would like to consider a ListView (responsible for displaying a list of objects) and DetailView (responsible for displaying information about a particular object).
Part 1 ,
Part 2 ,
Part 3 ,
Part 4Also, as before, I will be happy to get feedback from readers - if you find an error or inaccuracy in the article, please inform us that we will make the article better together.
Quick links to find methods
get_paginate_byget_allow_emptyget_context_object_nameget_objectget_slug_field')
Quick links to find attributes
paginate_bypaginator_classallow_emptycontext_object_nameobjectslug_fieldDisplaying a list of objects
Undoubtedly, this operation is required in the absolute majority of projects and, fortunately, it is provided for by the Django developers in the framework. The methods and attributes described in the previous part, I think do not need an additional description, so I will take into account only the new ones encountered.
In cases where it is necessary to display a huge number of objects, it is highly undesirable to display them all at the same time. In this case, a mechanism is required for paginated data output (pagination). The DetailView class inherits the admixture MultipleObjectMixin, which implements the functionality we need. To determine the number of objects per page, use the method
get_paginate_by , which by default returns an attribute value
paginate_by . With the help of the attribute, we can specify the number of objects displayed on 1 page without any special troubles.
Sometimes it becomes necessary to implement paginal output in our own way, for this we can pass our pagination class to the attribute
paginator_class . By default, this attribute contains a link to the standard Paginator class, which is implemented in the django.core.paginator module. Think twice, if you still decide to change it and check if the functionality you need is originally specified.
Attribute
allow_empty determines how to handle the situation when there is no object in the list. If we set the value of this attribute to True (the default), then an empty list of objects will be returned. If the value is False, error 404 will be returned. The value of this attribute is returned by the method
get_allow_empty . It can also be used if some additional verification or logic change is required.
In the template, our list of objects will be available by name, which is set using the attribute
context_object_name (or returned by
get_context_object_name , discussed in the previous article). Objects from the current page are in a variable named
object_list . Variable value
is_paginated (boolean) determines whether our list of objects is
paged . For more information about the pagination system, you can find out in the
documentation .
Attribute
object_list stores a list of our objects. It must be remembered that we must not forget to transfer the current page to our display for correct operation. The easiest way is to use named groups in our urls.py file.
url(r'^page/(?P<page>\d+)/$', PrivatePostList.as_view()),
Let's dilute the description with a small example of use:
And here, approximately, this may look like in a template:
{% extends 'base.html' %} {% block title %} {% endblock %} {% block content %} {% for post in object_list %} <div class="post"> <div class="post_name">{{ post.name }}</div> <div class="post_text">{{ post.text|safe }}</div> <div class="post_info">{{ post.author.username }}, {{ post.created_at|date:"dmY H:i" }}</div> </div> {% empty %} <p> :(</p> {% endfor %} {% if paginator.num_pages > 1 %} {% if page_obj.has_previous %} <a href="/page{{ page_obj.previous_page_number }}/">←</a> {% endif %} <span class="current_page">{{ paginator.number }}</span> {% if page_obj.has_next %} <a href="/page{{ page_obj.next_page_number }}">→</a> {% endif %} {% endif %} {% endblock %}
I think at this stage you can finish the review of the DetailView functionality, if I missed something important, please inform me and I will add the article.
View information about an individual object
Now it is time to consider the functionality of the class DetailView, which is responsible for viewing a single object.
To get a single object, we need to identify it by some parameter. Usually, the so-called unique primary key (pk, id) is used for this. Django also allows you to identify an object by the slug field, which can be any unique word. Of course, for SEO it is sometimes more convenient to use slug, if the objects are articles or a list of users (such as here, for example, on Habré). However, in other cases it makes no sense to use slug for identification (for example, viewing a comment or a personal message). In such cases, the primary key is used.
After we have chosen the method of identifying an object, we must inform Django of our choice by passing a variable with the appropriate name using the urls.py file path.
url(r'^post/(?P<pk>\d+)/$', PostDetail.as_view()),
Whatever method of identifying an object we accept, our object will be accessible using the method
get_object . This method alternately tries to find the variables pk and slug in the route, in this case a variable with the name pk will have a higher priority. Using the method
get_slug_field we can override the name of the slug field of our model. By default, this method returns an attribute value.
slug_field Our object is stored in the attribute
object .
from django.http import Http404 from django.views.generic.detail import DetailView from content.models import Post class PostView(DetailView): model = Post context_object_name = 'post' template_name = 'private_post_detal.html' def get_object(self): """ 404 login_required """ object = super(PostView, self).get_object() if not self.request.user.is_authenticated(): raise Http404 return object
At this stage, I think we can finish the consideration of the ListView and DetailView classes. In the next article I will try to write about FormView and work with forms. Thank you for taking the time to read. As usual, I am open to criticism and bug reports. I wish you all a good weekend!)