提示:(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、结果展示

Django——实现评论功能(包括评论回复)的更多相关文章

  1. Django使用forms来实现评论功能

    貌似Django从版本1.6开始就放弃了对自带的comments的使用,具体原因未查,但是现在使用Django的内部的模块也可以实现评论功能,那就是借助于forms模块,下面是我的一个小例子. 环境准 ...

  2. [个人网站搭建]·Django增加评论功能(Python3)

    [个人网站搭建]·Django增加评论功能 个人主页--> https://xiaosongshine.github.io/ 个人网站搭建github地址:https://github.com/ ...

  3. Django——实现最基础的评论功能(只有一级评论)

    我对评论功能的理解: --------(1)数据库建一个评论的表 --------(2)前端建一个提交评论的form表单 --------(3)表单提交评论内容后写入到数据库评论表中 -------- ...

  4. Django自带评论功能的基本使用

    1. 模块安装 pip install django-contrib-comments 2. 注册APP INSTALLED_APP=( #..., 'django_comments', 'djang ...

  5. django表格form无法保存评论排查步骤

    初学django项目,在网上找了个blog教程,还是很不错的,这里感谢一下博主https://www.zmrenwu.com/post/2/ 这个项目适合django初学者,是一个完整的blog项目 ...

  6. 我在做评论功能时学到的js一些思路

    在提交评论的时候,如何判断是一级评论还是二级评论(因为都是通过一个文本域提交评论),思路:声明一个全局变量,如果是回复(二级评论)那么会触发点击回复事件,在这个事件的回调函数里给全局变量设置为true ...

  7. VuePress 博客优化之增加 Vssue 评论功能

    前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 本篇讲讲 ...

  8. 一步步搭建自己的博客 .NET版(2、评论功能)

    前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做 ...

  9. vue教程2-07 微博评论功能

    vue教程2-07 微博评论功能 <!doctype html> <html> <head> <meta charset="utf-8"& ...

  10. React.js 小书 Lesson16 - 实战分析:评论功能(三)

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson16 转载请注明出处,保留原文链接和作者信息. 接下来的代码比较顺理成章了.修改 Commen ...

随机推荐

  1. 右键发送 (sendto),创建快捷方式到自定义的位置,不仅仅是复制,就像 发送到 桌面快捷方式 一样

    TL;DR 在 SendTo 文件夹里加上一文件夹的快捷方式后,在右键发送到这个文件夹的是这些文件的一个副本,实际上是一个复制的过程,有时候我们只希望是快捷方式,那就得另想办法了. 方案如下: 创建一 ...

  2. 用 JavaScript 刷 LeetCode 的正确姿势【进阶】

    之前写了篇文章 用JavaScript刷LeetCode的正确姿势,简单总结一些用 JavaScript 刷力扣的基本调试技巧.最近又刷了点题,总结了些数据结构和算法,希望能对各为 JSer 刷题提供 ...

  3. 初探Node-red结合阿里云数据库,定时显示数据

    在最近的项目中,隔壁项目组推荐了一个很好的基于node.js开源IOT框架Node-Red,它的优点很明显,使用可视化编程的方式,实现了大部分需要在物联网领域的技术,而且能很好的对接各个云平台,快捷部 ...

  4. 2021qwb [强网先锋]赌徒 Writeup + 环境复现

    2021 qwb [强网先锋]赌徒 Writeup + 环境复现(win10) 1.本地环境复现(win10+phpStudy2018) 将比赛文件复制到phpStudy的\phpStudy\PHPT ...

  5. vue 传参动态

    方法一: router/index.js { path: '/src/views/activitiesDetails', name: activitiesDetails, component: act ...

  6. burp暴力破解之md5和绕过验证码

    Burpsuite是一个功能强大的工具,也是一个比较复杂的工具 本节主要说明一下burp的intruder模块中的2个技巧 1.md5加密 我们在payload Processing中的add选项可以 ...

  7. Nginx 文件名逻辑漏洞(CVE-2013-4547)

    影响版本 Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7 漏洞成因 这个漏洞其实和代码执行没有太大关系,其主要原因是错误地解析了请求的URI,错误地获取到用户请求的文件名,导 ...

  8. 二、Windows安装与简单使用MinIO

    MinIO的官方网站非常详细,以下只是本人学习过程的整理 一.MinIO的基本概念 二.Windows安装与简单使用MinIO 三.Linux部署MinIO分布式集群 四.C#简单操作MinIO 一. ...

  9. tkinter 基础教程

    目录 介绍 模块 导入方式 API 使用 主窗口 运行窗口 组件列表介绍 Label 标签 Button 按钮 Options 属性选项 文本框 Entry 单行文本框 Text 多行文本框 文本框属 ...

  10. Spring Boot 配置中的敏感信息如何保护?

    在之前的系列教程中,我们已经介绍了非常多关于Spring Boot配置文件中的各种细节用法,比如:参数间的引用.随机数的应用.命令行参数的使用.多环境的配置管理等等. 这些配置相关的知识都是Sprin ...