Django blog development tutorial 8 – blog post details page

Time:2020-9-30

The home page shows a list of all the articles. When a user sees an article of interest, he or she can click the title of the article or continue reading. He should jump to the details page of the article to read the detailed content of the article. Now let’s develop the detail page of the blog. With the above foundation, the development process is the same: first configure the URL, that is, bind the relevant URL and view function together, then implement the view function, write the template and let the view function render the template.

Design the URL of the article detail page

Let’s review the URL of our home page view in blogurls.py In the document, we wrote:

blog/urls.py

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

After removing the domain name, the URL matching the home page view is actually an empty string. For the article details view, each article corresponds to a different URL. For example, we can design the view corresponding to the article details page as follows: when the user visits < website domain name > / post / 1 /, the content of the first article will be displayed, while when the user visits < website domain name > / post / 2 /, the content of the second article will be displayed. The number here represents the number of articles, that is, the ID value of the post record in the database. Follow this rule to bind the URL and view:

blog/urls.py

from django.conf.urls import url

from . import views

app_name = 'blog'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),
]

Django uses regular expressions to match the web addresses that users visit. herer'^post/(?P<pk>[0-9]+)/$'The entire regular expression just matches the URL rule we defined above. The meaning of this regular expression is that it starts with post /, followed by a number of at least one digit, and ends with / sign. For example, post / 1 /, post / 255 / etc. are all in accordance with the rules, and [0-9] + represents one or more digits. Besides, here(?P<pk>[0-9]+)Represents a named capture group. Its function is to capture the matching string in brackets from the URL visited by the user and pass it as a keyword parameter to its corresponding view functiondetail。 For example, when users access post / 255 / (note that Django does not care about the domain name, but only the relative URL after removing the domain name), the enclosed part(?P<pk>[0-9]+)If 255 is matched, the 255 will be passed in when the view function detail is called. In fact, the call of view function is like this:detail(request, pk=255)。 We have to capture the ID of the article from the URL here, because only in this way can we know which article the user is accessing.

Maybe the above regular expressions are a little difficult for you to understand. The part about regular expressions is not about Django, but about python. Django just uses Python’s re module to handle regular expressions here. Therefore, if you want to better understand the knowledge of regular expressions in Python, please check the document of re module in Python official documents.

In addition, we passed theapp_name='blog'Tell Django this urls.py Module belongs to blog application, which is called view function namespace. We see blogurls.py At present, there are two view functions, and they are aliased by the name attribute, which are index and detail. However, a complex Django project may have more than these view functions. For example, some third-party applications may also have view functions called index and detail. How to distinguish them and prevent conflicts? The method is through app_ Name to specify the namespace. How to use the namespace will be described below. If you forget to be in blogurls.py You may get a nomatchreversed exception next.

In order to easily generate the above URL, we use thePostDefine aget_absolute_urlMethod, attentionPostIt is a python class, in which we can define any method.

blog/models.py

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.six import python_2_unicode_compatible

@python_2_unicode_compatible
class Post(models.Model):
    ...

    def __str__(self):
        return self.title
    
    #Custom get_ absolute_ URL method
    #Remember from django.urls  Import the reverse function in
    def get_absolute_url(self):
        return reverse('blog:detail', kwargs={'pk': self.pk})

Notice theurl(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail')We set itname='detail'It’s useful here. See thisreverseFunction, the value of its first parameter is'blog:detail', which means under the blog applicationname=detailBecause we pass theapp_name = 'blog'It tells Django that the URL module belongs to the blog application, so Django can successfully find the view function with the name of detail under the blog application, soreverseThe function will parse the URL corresponding to the view function. The corresponding rule of detail here ispost/(?P<pk>[0-9]+)/This regular expression, and the regular expression part will be passed in laterpkReplace, so ifPostIf ID (or PK, where PK and ID are equivalent) is 255, thenget_absolute_urlThe function returns / post / 255 /, so that post generates its own URL.

Detail function writing view

The next step is to implement ourdetailView function:

blog/views.py

from django.shortcuts import render, get_object_or_404
from .models import Post

def index(request):
    # ...

def detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/detail.html', context={'post': post})

The view function is very simple. According to the article ID (that is PK, where PK and ID are equivalent) captured from the URL, the view function obtains the record with the article ID as the value in the database, and then passes it to the template. Notice here that we use the django.shortcuts Module importedget_object_or_404Method is used to return the corresponding one when the post corresponding to the incoming PK exists in the databasepostIf it does not exist, a 404 error will be returned to the user, indicating that the article requested by the user does not exist.

Write detail page template

The next step is to write a template file from the downloaded blog template (if you haven’t already downloaded it, pleaseclick here (download) single.html Copy to the templatesblog directory (and index.html At the same level of the directory), and then renamed detail.html 。 Your directory structure should look like this:

blogproject\
    manage.py
    blogproject\
        __init__.py
        settings.py
        ...
    blog/
        __init__.py
        models.py
        ,,,
    templates\
        blog\
            index.html
            detail.html

On the index page, thetitleandContinue reading buttonWrite a hyperlink to jump to, that is, an articlepostThe URL of the corresponding detail page allows users to jump to the detail page after clicking:

templates/blog/index.html

<article class="post post-1">
  <header class="entry-header">
    <h1 class="entry-title">
      <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
    </h1>
    ...
  </header>
  <div class="entry-content clearfix">
    ...
    <div class="read-more cl-effect-14">
      <a href="{{  post.get_ absolute_ URL}} "class =" more link "> read on < span class =" meta NAV "> → < / span ></a>
    </div>
  </div>
</article>
{% empty %}
  < div class = "no post" > articles that have not been published yet! </div>
{% endfor %}

Here we revise two places. The first is the title of the article:

<h1 class="entry-title">
  <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</h1>

We changed the value of the a tag’s attribute to{{ post.get_ absolute_ url }}。 Review the use of template variables, because get_ absolute_ The URL method (which we define in the post class) ReturnspostThe corresponding URL, so here{{ post.get_ absolute_ The URL}} will eventually be replaced with thispostIts own URL.

Similarly, the second change is to continue to read the button link:

<a href="{{  post.get_ absolute_ URL}} "class = more link" > read on < span class = "meta NAV" > →</span>
</a>

In this way, when we click the title of the home page article or continue to read the button, it will jump to the corresponding details page of the article. However, if you try to jump to the details page, you will find that the style is messy. This is in theReal Django blog home pageAs we have said, since we are directly copying templates, we have not handled static files properly. We can modify the import path of static files according to the methods described, but soon you will find that these static files need to be imported in any page. If you want to modify each page, it will be very troublesome, and the code is repetitive. Next, we will introduce the method of Django template inheritance to help us eliminate these duplicate operations.

Template inheritance

We see index.html Documents and detail.html Except for the different parts of the package in the main tag, other parts of the file are the same. We can extract the same part and put it in the base.html Inside. First, create a new one in the templates directory base.html File, your project directory should look like this:

blogproject\
    manage.py
    blogproject\
        __init__.py
        settings.py
        ...
    blog\
        __init__.py
        models.py
        ,,,
    templates\
        base.html
        blog\
            index.html
            detail.html

Put index.html Copy all contents of to base.html File, then delete the contents of the main label package and replace it with the following contents.

templates/base.html

...
<main class="col-md-8">
    {% block main %}
    {% endblock main %}
</main>
<aside class="col-md-4">
  {% block toc %}
  {% endblock toc %}
  ...
</aside>
...

Here, block is also a template tag, and its function is to occupy space. For example, here {% block main%} {% endblock main%} is a placeholder, and main is the name we give the block. Next, we will see the role of the block tag. At the same time, we also add a {% block TOC%} {% endblock TOC%} space holder under the side tag, because detail.html There will be an additional table of contents under the side tab. When there is nothing in {% block TOC%} {% endblock TOC%}, {% block TOC%} will not appear in the template. But when there is content in it, the template will display the content in the block.

In index.html We’re in the papersTopuse{% extends 'base.html' %}Inheritance base.html That’s how it works base.html In addition, fill in the contents of the index page in the {% block main%} {% endblock main%} package

templates/blog/index.html

{% extends 'base.html' %}

{% block main %}
    {% for post in post_list %}
        <article class="post post-1">
          ...
        </article>
    {% empty %}
        < div class = "no post" > articles that have not been published yet! </div>
    {% endfor %}
    <! -- simple paging effect
    <div class="pagination-simple">
        < a http: // ා "> previous page</a>
        < span class = "current" > page 6 of 11</span>
        < a http: // ා "> next page</a>
    </div>
    -->
    <div class="pagination">
      ...
    </div>
{% endblock main %}

So base.html Add the code in {% block main%} {% endblock main%} to the beginning index.html The code in it is the same. This is the role of template inheritance. The common part of the code is placed in the base.html On the other hand, different parts of other pages can be replaced by replacing the contents in the {% block main%} {% endblock main%}.

If you’re still a little confused about this kind of template inheritance, you can compare it to the inheritance of classes in Python. base.html It’s the parent class, index.html It’s a subclass. index.html Inherited base.html At the same time, it also has some contents. These contents can be added by “overriding” {% block main%} {% endblock main%} (regarding block as the attribute of parent class).

The detail page is easy to handle, and the inheritance is the same base.html , fill in {% block main%} {% endblock main%} detail.html What the page should display and fill in {% block TOC%} {% endblock TOC%} base.html The contents of the directory section that are not available in. However, the current directory is only bit data. We will implement how to automatically extract the directory from the article in the future.

templates/blog/detail.html

{% extends 'base.html' %}

{% block main %}
    <article class="post post-1">
      ...
    </article>
    <section class="comment-area">
      ...
    </section>
{% endblock main %}
{% block toc %}
    <div class="widget widget-content">
        < H3 class = "widget title" > Article contents</h3>
        <ul>
            <li>
                Features of the course</a>
            </li>
            <li>
                Who is suitable for this tutorial</a>
            </li>
            <li>
                < a http: // ා "> online preview</a>
            </li>
            <li>
                Resource list</a>
            </li>
            <li>
                Get help</a>
            </li>
        </ul>
    </div>
{% endblock toc %}

Modify some contents under the article tag to display the actual data of the article:

<article class="post post-{{ post.pk }}">
  <header class="entry-header">
    <h1 class="entry-title">{{ post.title }}</h1>
    <div class="entry-meta">
      <span class="post-category"><a href="#">{{ post.category.name }}</a></span>
      <span class="post-date"><a href="#"><time class="entry-date"
                                                datetime="{{ post.created_time }}">{{ post.created_time }}</time></a></span>
      <span class="post-author"><a href="#">{{ post.author }}</a></span>
      < span class = "comments link" > < a Ref. "> 4 Comments</a></span>
      < span class = "views count" > < a Ref. "> 588 reading</a></span>
    </div>
  </header>
  <div class="entry-content clearfix">
    {{ post.body }}
  </div>
</article>

Click the title of an article again from the home page or continue to read button to jump to the details page, you can see the expected effect!

Django blog development tutorial 8 - blog post details page

summary

The code for this section is located at:Step8: blog detail view

If you have problems, please ask for help in the following ways.

For more Django tutorials, visitBlog of dreamers