提示:(1)功能不全面,仅仅实现评论(2)样式简单
1、项目目录结构
2、模型
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、路由:
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、视图函数
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)注册页面
<!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)登录页面
<!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)首页
<!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)文章详情页
<!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、结果展示