Django——实现评论功能(包括评论回复)

提示:(1)功能不全面,仅仅实现评论(2)样式简单

 

1、项目目录结构

 

 

2、模型

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from django.db import models
from django.contrib.auth.models import User
 
 
class Article(models.Model):    #定义文章模型类
    title = models.CharField(max_length=100,verbose_name='文章标题')   #verbose_name是
    content = models.TextField(verbose_name='文章内容')
    publish_time = models.DateTimeField(auto_now_add=True,verbose_name='发布时间')
    author = models.ForeignKey(User,on_delete=models.DO_NOTHING,verbose_name='作者')
 
    class Meta:
        db_table = 'article_tb'     #定义表名
        verbose_name = '文章'       #后台显示
        verbose_name_plural = verbose_name    #后台显示的复数
 
 
 
 
class Comment(models.Model):    #定义评论模型
    article = models.ForeignKey(to=Article,on_delete=models.DO_NOTHING,verbose_name='评论文章')
    comment_content = models.TextField(verbose_name='评论内容')
    comment_author = models.ForeignKey(to=User,on_delete=models.DO_NOTHING,verbose_name='评论者')
    comment_time = models.DateTimeField(auto_now_add=True,verbose_name='评论时间')
    pre_comment = models.ForeignKey('self',on_delete=models.DO_NOTHING,null=True,verbose_name='父评论id'#父级评论,如果没有父级则为空NULL, "self"表示外键关联自己
 
    class Meta:
        db_table = 'comment_tb'
        verbose_name = '评论'
        verbose_name_plural = verbose_name

  

 

3、路由:

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib import admin
from django.urls import path,re_path
from myapp import views       #导入myapp中的视图函数
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('register/',views.register),            #用户注册路由
    path('user_login/',views.user_login),        #用户登录路由
    path('index/',views.index),                  #首页路由
    re_path('article_detail/(\d)/',views.article_detail),  #文章详情页路由,并传入文章的id
    path('comment_control/',views.comment_control)   #提交评论处理的路由
]

  

4、视图函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from django.http import JsonResponse
from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth                #使用Django的auth认证组件
from django.contrib.auth.models import User    #使用Django的认证组件需要使用User用户表
from myapp.models import Article               #导入Article模型
from myapp.models import Comment               #导入Comment模型
 
 
 
def register(request):  #用户注册函数
    if request.method == 'GET':
        return render(request,'register.html')   #返回一个注册的页面
    else:
        username = request.POST.get('username'#获取注册输入的信息
        password = request.POST.get('password')
        User.objects.create_user(username=username,password=password)  #在User表创建用户记录
        return HttpResponse('注册成功')
 
 
 
 
 
def user_login(request):   #用户登录函数
    if request.method == 'GET':
        return render(request,'user_login.html')
    else:
        username = request.POST.get('username')     #获取登录输入的信息
        password = request.POST.get('password')
        user = auth.authenticate(username=username,password=password)  #用户验证
        if user:
            auth.login(request,user)         #认证成功则保持登录状态
            return HttpResponse('登陆成功')
        else:
            return redirect('/user_login/'#认证失败则跳转到登录页面进行重新登录
 
 
 
 
 
 
def index(request):    #首页函数
    if request.user.username:      #判断用户是否已登录(用户名是否存在)
        all_article_list = Article.objects.all()    #取出所有的文章对象,结果返回一个QuerySet[]对象
        context = {
            'all_article_list': all_article_list
        }
        return render(request,'index.html',context=context)         #返回首页的页面,并将文章对象传到模板进行渲染
    else:
        return redirect('/user_login/')   #如果用户没有登录,则跳转至登录页面
 
 
 
 
 
 
def article_detail(request,article_id):
    if request.user.username:
        article = Article.objects.get(id=article_id)    #从数据库找出id=article_id的文章对象
        comment_list = Comment.objects.filter(article_id=article_id)  #从数据库找出该文章的评论数据对象
        context = {
               'article': article,
               'comment_list': comment_list
        }
        return render(request,'article_detail.html',context=context)  #返回对应文章的详情页面
    else:
        return redirect('/user_login/')
 
 
 
 
 
def comment_control(request):    #提交评论的处理函数
 
    if request.user.username:
        comment_content = request.POST.get('comment_content')
        article_id = request.POST.get('article_id')
        pid = request.POST.get('pid')
        author_id = request.user.id     #获取当前用户的ID
 
        Comment.objects.create(comment_content=comment_content,pre_comment_id=pid,article_id=article_id,comment_author_id=author_id)  #将提交的数据保存到数据库中
 
        article = list(Comment.objects.values('id','comment_content','pre_comment_id','article_id','comment_author_id','comment_time'))  #以键值对的形式取出评论对象,并且转化为列表list类型
 
        return JsonResponse(article,safe=False)   #JsonResponse返回JSON字符串,自动序列化,如果不是字典类型,则需要添加safe参数为False
    else:
        return redirect('/user_login/')

  

5、模板templates

(1)注册页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <h6>注册</h6>
    <form action="" method="post">    {# 注册提交信息的表单,POST方式提交注册信息 #}
        <input type="text" placeholder="用户名" name="username">
        <input type="password" placeholder="密码" name="password">
        <input type="submit" value="注册">
    </form>
 
</body>
</html>

  

(2)登录页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <h6>登录</h6>
    <form action="" method="post">    {# 登录时提交信息的表单,POST方式 #}
        <input type="text" placeholder="用户名" name="username">
        <input type="password" placeholder="密码" name="password">
        <input type="submit" value="登录">
    </form>
 
</body>
</html>

  

(3)首页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <style>
        .article{
            width: 80%;
        }
        .article_list{
            width: 100%;
            border: red 1px dashed;
        }
        .article .article_list th{
            text-align: center;
            border: 1px skyblue dashed;
        }
        .article .article_list td{
            text-align: center;
            border: 1px green dashed;
        }
    </style>
</head>
<body>
    <div class="article">
        <table class="article_list">
            <tr>
                <th>文章ID</th>
                <th>文章标题</th>
                <th>文章内容</th>
                <th>发布时间</th>
                <th>作者</th>
            </tr>
            {% for article in all_article_list %}
            <tr>
                <td>{{ article.id }}</td>
                <td><a href="/article_detail/{{ article.id }}/">{{ article.title }}</a>   {# 点击链接打开文章详情页,并传入文章的ID #}
                <td>{{ article.content }}</td>
                <td>{{ article.publish_time | date:"Y-m-d H:i:s"}}</td>
                <td>{{ article.author }}</td>
            </tr>
            {% endfor %}
 
        </table>
    </div>
</body>
</html>

  

(4)文章详情页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文章详情</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <style>
        .article_detail{
            width: 80%;
            margin-left: 100px;
        }
        .comment_post{
            width: 80%;
            margin-left: 100px;
        }
        .comment_show{
            width: 80%;
            margin-left: 100px;
        }
        #commentform_title {
            background-image: url(//static.cnblogs.com/images/icon_addcomment.gif);
            background-repeat: no-repeat;
            padding: 0 0 0 25px;
            margin-bottom: 10px;
        }
        .feedback_area_title {
            border-bottom: 1px solid #ddd;
            font-size: 14px;
            font-weight: bold;
            margin: 20px 0 10px;
        }
        #p{
            border: deepskyblue 1px dashed;
            background-color: antiquewhite;
        }
    </style>
</head>
<body>
    <div class="article_detail">    {# 文章详情区域的div #}
        <h4>{{ article.title }}</h4>
        <p>{{ article.content }}</p>
        <p>发布时间:{{ article.publish_time | date:"Y-m-d H:i:s"}}    作者:{{ article.author }}</p>
    </div>
 
 
    <div class="comment_post">      {# 提交评论区域的div #}
        <div id="commentform_title">发表评论</div>
        <textarea rows="10" cols="60" id="comment_content"></textarea>
        <p><button>提交评论</button></p>
    </div>
 
 
    <div class="comment_show">      {# 评论展示区域的div #}
        <div class="feedback_area_title">评论列表</div>
        <div class="comment_list">
            {% for comment in comment_list %}    {# 循环展示评论的数据 #}
                <div>
                    <p>第{{ forloop.counter}}楼 -> By:{{ comment.comment_author.username }} -> {{ comment.comment_time }} -> <button class="reply" username={{ comment.comment_author.username }} pk={{ comment.pk }}>回复</button></p>  {# 在此处定义一个回复按钮,用户实现子评论,并且自定义属性username和pk,用于下面回复功能的实现 #}
                    {% if comment.pre_comment_id %}   {# 判断评论是否有父级评论 #}
                        <p id="p">原评论内容:{{ comment.pre_comment.comment_content }}</p>  {# 如果有父级评论,则在中间显示父级评论的评论内容 #}
                    {% endif %}
                    <p>评论内容:{{ comment.comment_content }}</p>
                    <hr>
                </div>
            {% endfor %}
        </div>
    </div>
 
 
    {# 提交评论的JS,发送Ajax请求 #}
    <script>
        var pid = ""        {# 设置一个变量pid默认为空,用于后面作为数据库存储的父级评论的ID,如果没有父级评论则为空,子评论有父级评论 #}
        {# 提交评论按钮的点击事件 #}
        $(".comment_post p button").click(function (){
            $.ajax({
                url: '/comment_control/',
                type: 'post',
                data: {
                    comment_content: $("#comment_content").val(),  {# 提交的数据内容data #}
                    article_id: {{ article.id }},
                    pid: pid
                },
                success: function (res){            {# 本例中返回的数据仅仅用于在控制台打印而已 #}
                    console.log(res)                {# 控制台打印返回的数据 #}
                    $("#comment_content").val("")   {# 提交完成后,清空评论输入框的内容 #}
                    pid = ""                        {# 子评论提交完成后,将pid默认设置为空,恢复为默认的父评论 #}
 
                }
            })
        })
 
 
        {# 回复按钮的点击事件 #}
        $(".reply").click(function (){
            $("#comment_content").focus()       {# 回复按钮的事件,点击时,将光标聚集到评论输入框中 #}
            var val = "@" + $(this).attr("username") + "\n"    {# $(this)指代".reply"标签本身,获取这个标签的username值 #}
            $("#comment_content").val(val)      {# 回复时,自动在输入框加入:@要回复的人 #}
            pid = $(this).attr("pk")            {# 当点击回复时,父评论ID不再为空,此时修改为:对应评论的主键值ID #}
        })
 
    </script>
 
</body>
</html>

  

 

6、数据库表

 

 

 

 

7、结果展示

 

posted @   映辉  阅读(3933)  评论(1编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示