Python + Django4 to build a personal blog (16): Implementation of article comment function

In the previous article, we implemented the user registration function, and now the user management module has been completed.

Next, let’s implement another important function of the blog: article comments.

With the knowledge accumulation of article management, it is easier to implement the comment management function.

Write corresponding modules according to the MTV model.

Create App

Create a new App for comment management through the following code:

python manage.py startapp comment

Register App

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'article',
    'userprofile',
    # 新增'comment'代码,激活app
    'comment',
]

In order to show that the time when the comment was posted is China time, modify the time zone setting TIME_ZONEto Shanghai's time zone.

TIME_ZONE = 'Asia/Shanghai'

Define model

from django.db import models
from django.contrib.auth.models import User
from article.models import Article

# 博文的评论
class Comment(models.Model):
    article = models.ForeignKey(Article,
        on_delete=models.CASCADE,
        related_name='comments'
    )
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='comments'
    )
    body = models.TextField()
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('created',)

    def __str__(self):
        return self.body[:20]

In the model we define two foreign keys

If a common key is the primary key in one relationship, then the common key is called a foreign key in another relationship .

  • articleis the article being commented on
  • useris the publisher of the comment

Migrate data

Create form

Create a new comment form

from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['body']

In the comments table, there are two fields that belong to foreign keys. For the foreign key fields, the Djangointernal logic can be automatically generated in association with the external data table.

We actually only need the foreground processing fields in the form body.

Create RRL

Add django4blog/urls.pycomment management URL:

from django.contrib import admin
from django.urls import path, re_path
# 引入app视图
import article.views
import userprofile.views
import comment.views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('hello/', article.views.hello),
    re_path(r'^$', article.views.article_list),
    path('list/', article.views.article_list, name='list'),  # 展示文章
    path('detail/<int:id>/', article.views.article_detail, name='detail'),  # 文章详情
    path('create/', article.views.article_create, name='create'),  # 写文章
    path('delete/<int:id>/', article.views.article_delete, name='delete'),# 删除文章
    path('update/<int:id>/', article.views.article_update, name='update'),    # 更新文章
    path('login/', userprofile.views.user_login, name='login' ),
    path('logout/', userprofile.views.user_logout, name='logout' ),
    path('register/', userprofile.views.user_register, name='register' ),
    # 增加评论管理
    path('post-comment/<int:article_id>/', comment.views.post_comment, name='post_comment' ),
]

Create view

The commented view function is as follows:

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse

from article.models import Article
from .forms import CommentForm

# 文章评论
@login_required(login_url='/login/')
def post_comment(request, article_id):
    article = get_object_or_404(Article, id=article_id)
    # 处理 POST 请求
    if request.method == 'POST':
        comment_form = CommentForm(request.POST)
        if comment_form.is_valid():
            new_comment = comment_form.save(commit=False)
            new_comment.article = article
            new_comment.user = request.user
            new_comment.save()
            return redirect(article)
        else:
            return HttpResponse("表单内容有误,请重新填写。")
    # 处理错误请求
    else:
        return HttpResponse("发表评论仅接受POST请求。")

get_object_or_404():It has Model.objects.get()basically the same functionality as . The difference is that in a production environment, if the user requests an object that does not exist, (server internal error) Model.objects.get()will be returned Error 500, and get_object_or_404()Error 404 will be returned. In contrast, returning a 404 error is more accurate.

redirect():Return to an appropriate urlmedium: that is, after the user sends a comment, he is redirected to the article details page. When its parameter is an object, the method of Modelthis object will be automatically called . Therefore, the model will be modified immediately .Modelget_absolute_url()article

Modify article model

article/models.pyAdd get_absolute_url()method to article model :

# 博客文章数据模型
class Article(models.Model):
    # 文章id,主键
    id = models.AutoField(primary_key=True)
    # 文章作者
    author = models.CharField(max_length=100)
    # 文章标题,models.CharField 为字符串字段,用于保存较短的字符串,比如标题
    title = models.CharField('标题',max_length=100)

    # 文章正文,保存大量文本使用 TextField
    body = models.TextField('文章正文')

    # 文章创建时间,参数 default=timezone.now 指定其在创建数据时将默认写入当前的时间
    created = models.DateTimeField(default=timezone.now)

    # 文章更新时间,参数 auto_now=True 指定每次数据更新时自动写入当前时间
    updated = models.DateTimeField(auto_now=True)
    # 获取文章地址
    def get_absolute_url(self):
        return reverse('detail', args=[self.id])

reverse()Route redirection is implemented by returning the url of the article details page through the method.

Modify article details view

The comment module needs to be displayed on the article details page, so the context of the comment module must also be passed to the template.

Therefore the modification article/views.pyis article_detail():

# 文章详情
def article_detail(request,id):
    # 取出相应的文章
    article = Article.objects.get(id=id)
    # 取出文章评论
    comments = Comment.objects.filter(article=id)
    # 需要传递给模板的对象
    context = {'article': article, 'comments': comments}
    # 载入模板,并返回context对象
    return render(request, 'article/detail.html', context)

Modify article details template

<!-- extends表明此页面继承自 base.html 文件 -->
{% extends "base.html" %}
{% load static %}

<!-- 写入 base.html 中定义的 title -->
{% block title %}
    文章详情
{% endblock title %}

<!-- 写入 base.html 中定义的 content -->
{% block content %}

    <!-- 文章详情 -->
    <div class="container">
        <!--    <div class="row">-->
        <!-- 标题及作者 -->
        <h1 class="col-12 mt-4 mb-4">{
   
   { article.title }}</h1>
        <div class="col-12 alert alert-primary">
            <div class="col-12">
                <a>作者:{
   
   { article.author }}</a>
                &nbsp
                <a>{
   
   { article.created|date:'Y-m-d H:i:s' }}</a>
                &nbsp
                <a href="#" data-bs-toggle="modal" data-bs-target="#myModal">删除文章</a>
                <!-- 新增一个隐藏的表单 -->
                <form
                        style="display:none;"
                        id="safe_delete"
                        action="{% url "delete" article.id %}"
                        method="POST"
                >
                    {% csrf_token %}
                    <button type="submit">发送</button>
                </form>
                &nbsp
                <a href="{% url "update" article.id %}">编辑文章</a>
            </div>
        </div>
        <!-- 文章正文 -->
        <div class="col-12">
            <p>{
   
   { article.body }}</p>
        </div>
        <!--    </div>-->
    <div class="container">
    <div class="col-12">
        <!-- 发表评论 -->
        <hr>
        {% if user.is_authenticated %}
            <div>
                <form
                        action="{% url "post_comment" article.id %}"
                        method="POST"
                >
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="body">
                            <strong>
                                我也要发言:
                            </strong>
                        </label>
                        <textarea
                                type="text"
                                class="form-control"
                                id="body"
                                name="body"
                                rows="2"></textarea>
                    </div>
                    <br>
                    <!-- 提交按钮 -->
                    <button type="submit" class="btn btn-primary ">发送</button>
                </form>
            </div>
            <br>
        {% else %}
            <br>
            <h5 class="col-12 ">
                请<a href="{% url 'login' %}">登录</a>后回复
            </h5>
            </h5>
            <br>
        {% endif %}
    </div>
    </div>
        <!-- 显示评论 -->
        <h4>共有{
   
   { comments.count }}条评论</h4>
        <div>
            {% for comment in comments %}
                <hr>
                <p>
                    <strong style="color: pink">
                        {
   
   { comment.user }}
                    </strong> 于
                    <span style="color: green">
                    {
   
   { comment.created|date:"Y-m-d H:i:s" }}
                </span> 时说:
                </p>
                <pre style="font-family: inherit; font-size: 1em;">
                {
   
   { comment.body }}</pre>
            {% endfor %}
        </div>
    </div>
    </div>

{% endblock content %}
  • actionWhich url should the specified data in the form component be submitted to?
  • What is shown in the comment comments.countis the method built into the template object to count the contained elements.
  • |date:"Y-m-d H:i :s":You are already familiar with the pipe character, which is used to "paste" certain properties or functionality to an object. This is used to format how dates are displayed.
  • <pre>Defining preformatted text, the most critical role in our project is to preserve spaces and newlines. This tag will change the font, size, etc. of the text, so use the style attribute to redefine the relevant content. Try <pre>replacing with divand enter multiple lines of text to try the effect.

Run tests

After running, check the details page. If you are not logged in, you will be prompted to log in to reply to the comment.

Log in to post a comment

Conclusion

So far we have completed the core functions of comment management, publishing and display. In fact, some websites also provide the function of modifying and deleting comments.

The implementation process is similar to the modification and deletion of articles. You can complete the relevant development by yourself.

The core functional modules of our blog website, including articles, users and comments, are basically completed.

Next we will complete some practical small functional points of the blog.

For example, paging, sorting and search, etc.

Guess you like

Origin blog.csdn.net/agelee/article/details/127211000