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、结果展示
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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框架的用法!