In this tutorial, we’ll start developing the home page functionality. During the development, you’ll learn about the general view class in Django, the paginator object, and the use of the foreignKey.

Results demonstrate

The overall function

We can first through the site demo address to browse the effect of the home page. Our home page, more concise and generous, let a person at a glance. My goal here is to get you to focus on learning Django and not on the fancy web effects.

We disassemble the home page into four small business modules to develop, respectively: list display, paging function, search function, classification function. Below, we explain the development of these four functional modules respectively.

The development train of thought

The basic idea of developing a function is: first create a new application, and then analyze the business involved in the function, so as to analyze the required database fields, and then write the model, and then it is the display stage, through the URL routing configuration view function, to display the data in the model.

Ok, let’s create the application by command, named video. After that, Django will create a new video folder for us.

python3 manage.py startapp video
Copy the code

The following functional modules are developed under the application (Video).

model

Here, we need to establish two models, namely classification table and video table. They are many-to-one relationships (one category for multiple videos, one video for one category).

First, we write the Classification table. Under model.py, we type the following code. The fields are title(category name) and Status (enabled or not)

class Classification(models.Model):
    list_display = ("title",)
    title = models.CharField(max_length=100,blank=True, null=True)
    status = models.BooleanField(default=True)

    class Meta:
        db_table = "v_classification"
Copy the code

Fields that

  • Title Category name. The data type is CharField and the maximum length is max_length=100. Null =True is allowed
  • Status Whether to enable it. The data type is BooleanField and defaults to default=True
  • Db_table table name

Then write the Video model, according to the website business, we set the title(title), DESC (description), classification(classification), file(Video file), cover(cover), status(release status) and other fields. Classification is a ForeignKey ForeignKey field, indicating that a classification corresponds to multiple videos, and one video corresponds to one classification (many-to-one).

class Video(models.Model):
    STATUS_CHOICES = (
        ('0'.'In release'),
        ('1'.'Not published'),
    )
    title = models.CharField(max_length=100,blank=True, null=True)
    desc = models.CharField(max_length=255,blank=True, null=True)
    classification = models.ForeignKey(Classification, on_delete=models.CASCADE, null=True)
    file = models.FileField(max_length=255)
    cover = models.ImageField(upload_to='cover/',blank=True, null=True)
    status = models.CharField(max_length=1 ,choices=STATUS_CHOICES, blank=True, null=True)
    create_time = models.DateTimeField(auto_now_add=True, blank=True, max_length=20)

Copy the code

Fields that

  • Title Video title. The data type is charField and the maximum length is max_length=100. Null =True is allowed
  • Desc Video description. The data type is charField and the maximum length is max_length=255. Null =True is allowed
  • File Video file address. The data type is fileField. It stores the address of the video file. In the future video management, we will explain the uploading of the video in detail.
  • Cover Video cover. The data type is ImageField. Store directory upload_to=’cover/’, null=True allowed
  • Status Video status. Is a select state, set multiple select grandparents with Choices.
  • Create_time Creation time. The data type is DateTimeField. Set the automatic generation time auto_now_add=True

ForeignKey represents a one-to-many association. For example, here we have the relationship between video and classification. A video can only correspond to one category, and there can be multiple videos under one category. For more information about ForeinkKey, see the official introduction of ForeignKey

The list shows

To access the home page, routes must be configured. Create the urls.py file under video and write the following code

from django.urls import path
from . import views

app_name = 'video'
urlpatterns = [
    path('index', views.IndexView.as_view(), name='index'),]Copy the code

A PATH statement represents a piece of routing information. So we can in the browser input 127.0.0.1:8000 / video/index to access the home page.

Displaying list data is very simple, and we use django’s built-in view template class ListView to display it. First, we write an IndexView class in view.py to display list data. Type the following code

class IndexView(generic.ListView):
    model = Video
    template_name = 'video/index.html'
    context_object_name = 'video_list'  
Copy the code

Here, we use django’s general-purpose ListView class. Listviews are easy to use, and can render data from a database to the front end with a few lines of code. For example, in the code above, we configure

  • Model = Video, applied to the Video model
  • Template_name = ‘video/index.html’, telling ListView to use the template file we have created.
  • Context_object_name = ‘video_list, context variable names, tell ListView in front in the template file, you can use the variable name to display the data.

Then, under the templates folder, we created the Video directory to store the video related template files. First, we created the home file index.html. And display the data just obtained.

<div class="ui grid">
    {% for item in video_list %}
    <div class="four wide column">
        <div class="ui card">
            <a class="image">
                {% thumbnail item.cover "300x200" crop="center" as im %}
                <img class="ui image" src="{{ im.url }}">
                {% empty %}
                {% endthumbnail %}
                <i class="large play icon v-play-icon"></i>
            </a>
            <div class="content">
                <a class="header">{{ item.title }}</a>
                <div class="meta">
                    <span class="date"> published in {{item. Create_time | time_since}} < / span > < / div > < div class ="description"> {{item. View_count}} time watching < / div > < / div > < / div > < / div > {% empty %} < h3 > temporarily no data < / h3 > {% endfor %} < / div >Copy the code

The video_list is rendered to the front end through the for loop. Here we use django’s built-in tags, such as the for statement and empty statement. These are all very common django statements. We’ll come across this a lot later in the tutorial.

In addition, you use the thumbnail tag to display images, a popular Python library that is often used to display images.

The following output is displayed:

Classification function

Before writing the classification function, we’ll look ata callback called get_context_data(), which is a function in the ListView view class. In get_context_data(), we can pass some extra content to the template. So we can use this function to pass classification data.

To use it, it’s simple.

Simply append the get_context_data() implementation to the IndexView class.

class IndexView(generic.ListView):
    model = Video
    template_name = 'video/index.html'
    context_object_name = 'video_list' 

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        classification_list = Classification.objects.filter(status=True).values()
        context['classification_list'] = classification_list
        return context
Copy the code

In the above code, we will classify the data by Classification. The objects. The filter (status = True). The values () from the database to filter out inside, and then assign classification_list, finally in the context of a dictionary.

In the front template (templates/video/index. The HTML), can be used classification_list to collect data. Add code

<div class="classification">
    <a class="ui red label" href=""> all </a> {%for item in classification_list %}
    <a class="ui label" href="">{{ item.title }}</a>
    {% endfor %}
</div>
Copy the code

It should look like this

Of course, now that we have just achieved the classification display effect, we need to continue to achieve the click effect, that is, click on different categories to display different video lists.

Let’s start by attaching an href link to each category button

<div class="classification">
    <a class="ui red label" href="{% url 'home' %}"> all </a> {%for item in classification_list %}
    <a class="ui label" href="? c={{ item.id }}">{{ item.title }}</a>
    {% endfor %}
</div>
Copy the code

By adding? C ={{item.id}} c={{item.id}} c={{item.id}} c={{item.id}} c={{item.id}} GET (“c”, None) to c and check if c is None. If c is None, return all. Call get_object_or_404(Classification, PK =self.c) to retrieve the current class and classified.video_set to retrieve the foreign key data.

    def get_queryset(self):
        self.c = self.request.GET.get("c", None)
        if self.c:
            classification = get_object_or_404(Classification, pk=self.c)
            return classification.video_set.all().order_by('-create_time')
        else:
            return Video.objects.filter(status=0).order_by('-create_time')

Copy the code

For more information about how to use ForeignKey, please refer to here

paging

In Django, there is a ready-made paging solution that saves us developers a lot of work. For simple paging, just configure paginate_by.

class IndexView(generic.ListView):
    model = Video
    template_name = 'video/index.html'
    context_object_name = 'video_list'
    paginate_by = 12
    c = None
Copy the code
  • Painate_by = 12 Displays 12 lines per page

Now that the pagination data for each page is displayed correctly, improve the page number bar at the bottom.

The page number list needs to be done by both the view class and the template, so let’s write the view class first. We’ve already written get_context_data, the main function of which is to pass extra data to the template. Here, we use get_context_data to pass page number data.

Let’s start by defining a utility function called get_page_list. In the root directory of your project, create a new file called helpers.py that acts as a global utility class for your various utility functions. Put get_page_list inside helpers.py. This function is used to produce a list of page numbers, and it can be used here, but it can be called elsewhere in the future.

def get_page_list(paginator, page):

    page_list = []

    if paginator.num_pages > 10:
        if page.number <= 5:
            start_page = 1
        elif page.number > paginator.num_pages - 5:
            start_page = paginator.num_pages - 9
        else:
            start_page = page.number - 5

        for i in range(start_page, start_page + 10):
            page_list.append(i)
    else:
        for i in range(1, paginator.num_pages + 1):
            page_list.append(i)

    return page_list
Copy the code

Paging logic:

ifPage >=10: If current page <=5, the start page is 1. Current page >(Total page -5), the start page is (Total page -9). In other cases, the start page is (Current page -5).Copy the code

For example:

Case 1: current page ==5 then the page number list is [1,2,3,4,5,6,7,8,9,10] Case 2: Current page ==8 then the page number list is [3,4,5,6,7,8,9,10,11,12] Case 3: The current page = = 15 pages list as,8,9,10,11,12,13,14,15,16 [7]Copy the code

Of course, if you look at this logic, it’s a little confusing, so I encourage you to read the code and try it out a few times.

Once we get the page number list, we continue rewriting the get_context_data() function. Append the obtained ClassiFICation_list to the context dictionary.

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        paginator = context.get('paginator')
        page = context.get('page_obj')
        page_list = get_page_list(paginator, page)
        classification_list = Classification.objects.filter(status=True).values()
        context['c'] = self.c
        context['classification_list'] = classification_list
        context['page_list'] = page_list
        return context
Copy the code

Paginator = context.get(‘paginator’) Page = context.get(‘page_obj’). We just need to know that context.get(‘page_obj’) returns the current page number, and context.get(‘paginator’) returns the pagination object, and that’s all. For more detailed introduction, please refer to the official.

When the data is passed to the template, the template is responsible for displaying it.

Because paging is quite common, we need to take it out and wrap it in a separate file, so we create a templates/base/page_nav.html file. Then in index.html we include that file.

{% include "base/page_nav.html" %}
Copy the code

Open up page_nav.html and write the code

{% if is_paginated %}
<div class="video-page">
    <div class="ui circular labels">
        {% if page_obj.has_previous %}
        <a class="ui circular label" href="? page={{ page_obj.previous_page_number }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}">&lt; </a> {% endif %} {%for i in page_list %}
        {% if page_obj.number == i %}
        <a class="ui red circular label">{{ i }}</a>
        {% else %}
        <a class="ui circular label" href="? page={{ i }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}">{{ i }}</a>
        {% endif %}
        {% endfor %}
        {% if page_obj.has_next %}
        <a class="ui circular label" href="? page={{ page_obj.next_page_number }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}">&gt; </a> {% endif %} </div> </div> {% endif %}Copy the code

In the above code, we used several properties of the page_obj object: has_previous, previous_page_number, and next_page_number. Through these attributes, complex page number display effect can be realized. And that’s what we added in the href

{% if c %}&c={{c}}
Copy the code

Represents the ID of a category.

The search function

To implement a search, we need a search box

Because the search box is many pages need, so we write code templates/base/header. The HTML file.

<div class="ui small icon input v-video-search">
    <input class="prompt" value="{{ q }}" type="text" placeholder="Search video" id="v-search">
    <i id="search" class="search icon" style="cursor:pointer;"></i>
</div>
Copy the code

The code for hitting search or enter is in static/js/header.js.

We also need to configure the route and add a line of routes to search for.

app_name = 'video'
urlpatterns = [
    path('index', views.IndexView.as_view(), name='index'),
    path('search/', views.SearchListView.as_view(), name='search'),]Copy the code

The view class to which the search route points is SearchListView

Let’s write the code for our SearchListView

class SearchListView(generic.ListView):
    model = Video
    template_name = 'video/search.html'
    context_object_name = 'video_list'
    paginate_by = 8
    q = ' '

    def get_queryset(self):
        self.q = self.request.GET.get("q"."")
        return Video.objects.filter(title__contains=self.q).filter(status=0)

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(SearchListView, self).get_context_data(**kwargs)
        paginator = context.get('paginator')
        page = context.get('page_obj')
        page_list = get_page_list(paginator, page)
        context['page_list'] = page_list
        context['q'] = self.q
        return context
Copy the code

Filter (title__contains=self.q). Filter (status=0) title__contains= q Use filter to filter out the data. There are two filters, the first filter for search keywords and the second filter for status published videos.

In addition, get_context_data is used to store additional data, including paging data and q keywords.

The configuration template file is templates/video/search. HTML

So the template code is in search.html

<div class="ui unstackable items">

    {% for item in video_list %}
    <div class="item">
        <div class="ui tiny image">
            {% thumbnail item.cover "300x200" crop="center" as im %}
            <img class="ui image" src="{{ im.url }}">
            {% empty %}
            {% endthumbnail %}
        </div>
        <div class="middle aligned content">
          <a class="header" href="{% url 'video:detail' item.pk %}"> {{item. The title}} < / a > < / div > < / div > {% empty %} < h3 > temporarily no data < / h3 > < / div > {{% endfor %} % include"base/page_nav.html" %}
Copy the code

Effect of search function