HelloDjango of 08: Developing a blog post details page


Author: HelloGitHub- Dream figure

Sample code relates to text, it has been updated to synchronize HelloGitHub-Team warehouse

Home show a list of all articles, when users see articles of interest, he clicks the title of the article or continue reading button should jump to the article details page to see the details of the article. Now let's develop blog details page, with the front of the base, the development process is the same: the first configured URL, that is to bind together the relevant URL and view function, and then implement the view function, write a template and let view template rendering function.

Design Articles page URL details

Recall URL view of our home page, in blog \ urls.py file, we wrote:

blog/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

URL Home view match after removing the domain name is actually an empty string. For details view the article, each article corresponds to a different URL. For example, we can view the corresponding article details page designed to look like this: When a user accesses <domain> / posts / 1 /, the display of the contents of the first article, and when the user visits <domain> / posts / 2 /, the display of the contents of the second article, where the first number represents several articles, namely id values ​​in the database Post records. In accordance with the following rules to bind the URL and view:

blog/urls.py

from django.urls import path

from . import views

app_name = 'blog'
urlpatterns = [
    path('', views.index, name='index'),
    path('posts/<int:pk>/', views.detail, name='detail'),
]

Here 'posts/<int:pk>/'exactly match the URL rules we defined above. The meaning of this rule is to posts / beginning, followed by an integer, and ending / symbols, such as posts / 1 /, posts / 255 / and the like are in line with the rules, in addition there <int:pk>are special rules written django route matches, its role is from a URL matching the user's access to the digital capture key as a parameter to a function of the corresponding view detail. For example, when a user accesses posts / 255 / time (note django domain name does not care, but only care about the relative URL after the domain name removed), <int:pk>matched 255, then the 255 will be passed when calling into the view function detail, its parameter name is a colon specify the name behind pk, in fact, call the view function like this: detail(request, pk=255). Here we must capture the id of the article from the URL, because the only way we can know exactly which users access the article.

Tip:

django routes matching rules There are many types, except where the integer type int, and str character type, uuid, etc., may be learned by the official document: Path Converters

In addition We app_name='blog'tell django urls.py this module is part of the blog application, this technique is called the view function namespace. We see blog \ urls.py There are two views functions, and functions to these views taken by the alias name attributes, namely, index, detail. However, a complex project may be more than these django view function, for example, some third-party applications may also have called index, detail view function, then how to distinguish them, to prevent conflict it? The method is to specify the namespace by app_name, how namespace specific use will be described below. If you forget to add this sentence in the blog \ urls.py in, then you might get a NoMatchReversed exception.

In order to easily generate the URL described above, we Postdefine a class get_absolute_urlmethod, note that Postin itself is a Python class, class, we can define any method.

blog/models.py

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

class Post(models.Model):
    ...

    def __str__(self):
        return self.title
    
    # 自定义 get_absolute_url 方法
    # 记得从 django.urls 中导入 reverse 函数
    def get_absolute_url(self):
        return reverse('blog:detail', kwargs={'pk': self.pk})

Notes that URL configuration path('posts/<int:pk>/', views.detail, name='detail'), we set name='detail'here came in handy. See this reversefunction, the value of its first argument is 'blog:detail', the meaning is the blog application name=detailfunction, as we are by the above app_name = 'blog'told django this URL module is part of the blog application, so django able to successfully find the next blog application name is a detail view of the function, then reversethe function will function to parse the view corresponding to the URL, the rule here is that corresponding detail posts/<int:pk>/int portion is passed after the argument pkalternative, so if Postthe id (or pk, pk and where id equivalent) is 255, then the get_absolute_urlfunction returns is / posts / 255 /, so Post generates their own URL.

Write detail view function

Then there is the realization of our detailview of the 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})

View function is very simple, it is according to our captured from the URL of the article id (ie pk, where pk and id are equivalent) get a record id to the value of the article database, and then passed to the template. Note that we use to import from django.shortcuts module get_object_or_404method, its role is when the incoming pk corresponding Post in the database exists, it returns the corresponding post, if not, give the user returns a 404 error, indicating that the user request the article does not exist.

Written details page template

The next step is to write the template file, downloaded from the blog template (if you have not downloaded, please click here to download) are copied to the single.html templates \ directory under the blog (and index.html at the same level directory), and then changed its name to detail.html. At this point 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

In the index page blog post list title and continue reading button written on a hyperlink to jump link that article postcorresponding URL details page, so that users can click to jump to the detail page:

templates/blog/index.html

<article class="post post-{{ post.pk }}">
  <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">继续阅读 <span class="meta-nav">→</span></a>
    </div>
  </div>
</article>
{% empty %}
  <div class="no-post">暂时还没有发布的文章!</div>
{% endfor %}

Here we modify two places, the first is the title of the article at:

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

We href attribute value of a changed tag {{post.get_absolute_url}}. Review the use of template variables, due get_absolute_url this method (we define in the Post class) returns the postcorresponding URL, so here {{post.get_absolute_url}} will eventually be replaced by the postown URL.

Similarly, the modification is to continue at the second reading button link:

<a href="{{ post.get_absolute_url }}" class="more-link">继续阅读 <span class="meta-nav">→</span>
</a>

So that when we click on the title of the article or the Home button will jump to continue reading the article corresponding to the details page. However, if you try to jump to the details page, you will find that the style is chaos. This is from the "streaking" to "skin" blog talked about, since we are a direct copy of the template, but also did not correctly handle static files. We can modify the path to introduce static files in accordance with the method introduced, but soon you will find all you need to import static files on any page, each page must if changes will be very troublesome, and the code is repeated. Here are just django template inheritance way to help us eliminate these repeat operations.

Template inheritance

We see the index.html file and detail.html files in addition to different parts of the main label of the package, the other places are the same, we can put the same portion of the extracted and put in base.html. First create a new file in the templates directory base.html, this time your project directory should become like this:

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

Copy all the contents to base.html index.html file, and then delete the contents of the package main label, replaced 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 is a template block tag, its role is occupying. For example where {% block main%} {% endblock main%} is a placeholder block, main we give the name of the block fetch. Here we see the role of block labels. We also added under the tag aside a {% block toc%} {% endblock toc%} placeholder box, because detail.html will be more than a directory bar under the label aside. When {% block toc%} When {% endblock toc%} Nothing, {% block toc%} {% endblock toc%} does not appear in the template. But the content of which is that the template will display the contents of block.

In index.html, we in the file topmost use {% extends 'base.html' %}inheritance base.html, so put base.html code in succession over the other in {% block main%} {% endblock main%} wrapped in place to fill index content of the page should be displayed:

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">暂时还没有发布的文章!</div>
    {% endfor %}
    <!-- 简单分页效果
    <div class="pagination-simple">
        <a href="#">上一页</a>
        <span class="current">第 6 页 / 共 11 页</span>
        <a href="#">下一页</a>
    </div>
    -->
    <div class="pagination">
      ...
    </div>
{% endblock main %}

Such base.html in the code with {% block main%} {% endblock main%} index.html in the code and the code in the beginning of the same. This is the template inherit the role of the public portion of the code in base.html years, and various other parts of the page by replacing {% block main%} {% endblock main%} placeholder tag of the content.

If you're still a little confused on this template inheritance, this analogy can inherit inheritance and classes in Python. base.html is the parent class, index.html is the subclass. index.html inherits everything in base.html, while some of its own content, which through the "overwriting" {% block main%} {% endblock main%} (block seen as the parent class properties) to add content.

page simply deal with detail, the same inheritance base.html, the {% block main%} {% endblock main%} was filled detail.html content page to be displayed, and the {% block toc%} {% endblock toc %} fill in part of the contents of the directory in base.html not. But the current directory only placeholder data, we will achieve in the future how to automatically extract from the article directory.

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">文章目录</h3>
        <ul>
            <li>
                <a href="#">教程特点</a>
            </li>
            <li>
                <a href="#">谁适合这个教程</a>
            </li>
            <li>
                <a href="#">在线预览</a>
            </li>
            <li>
                <a href="#">资源列表</a>
            </li>
            <li>
                <a href="#">获取帮助</a>
            </li>
        </ul>
    </div>
{% endblock toc %}

Modify some content under article tag, let 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 href="#">4 评论</a></span>
      <span class="views-count"><a href="#">588 阅读</a></span>
    </div>
  </header>
  <div class="entry-content clearfix">
    {{ post.body }}
  </div>
</article>

Click again on the title of an article from the front page or continue reading button to jump to the details page, you can see the desired effect!


Welcome to public attention HelloGitHub number, access to information and content more open source projects

Guess you like

Origin www.cnblogs.com/xueweihan/p/11353675.html