js+mysql实现论坛回复功能_django框架之BBS项目之评论功能

本文详细介绍了如何在Django框架下实现论坛评论功能,包括评论的发表、展示、点赞和回复。内容涵盖了前端js与后端mysql的交互,评论的AJAX动态加载,以及使用Django的事务处理确保数据一致性。此外,还讨论了模板语言中的JS代码、字符串格式化输出以及事件委托等技术。
摘要由CSDN通过智能技术生成

内容回顾

1. BBS项目 CMS

1. 登录

1. form组件

2. auth模块

3. 验证码

2. 注册

1. form组件

1. 生成html代码

直接for循环form_obj,就能够遍历所有字段

2. 验证

1. 默认的那些验证

2. 正则的验证

3. 全局钩子做确认密码的验证

4. 判断用户名是否已经存在

1. input框失去焦点就发ajax到后端判断

2. form组件中使用局部钩子来判断

2. auth模块 --> 扩展auth_user表 --> create_user()

1. UserInfo这个类里面,avatar是一个FileField

avatar = models.FileField(upload_to="avatars/", default="avatars/default.png")

2. 注意事项:

1. FileField保存的是一个路径,而不是一个文件

2. upload_to:具体保存的文件路径就会在media目录下

3. 上传头像

1. ajax如何上传文件

2. Django中media的配置

1. settings.py中:

- MEDIA_URL:别名

- MEDIA_ROOT:给用户上传的所有文件指定一个存放目录

2. urls.py中:

from django.views.static import serve

from django.conf import settings

url(r'^media/(?P.*)', serve, {"document_root": settings.MEDIA_ROOT})

3. 博客首页

1. 文章列表(排样式)

2. 分页

1. 封装的要彻底

2. 封装后的结果要有普适性(url要写成配置项)

4. 个人博客主页

1. 分类

1. 文章分类

2. 文章标签

2. 日期归档

1. 日期格式化函数    --> MySQL内置的函数都有哪一些?      --> 《漫画数据库》

1. MySQL:DATE_FORMAT('字段', '格式')

2. sqlite:strftime('格式', '字段')

2. ORM中如何执行原生的SQL语句

1. 使用extra()在执行ORM查询的同时,嵌入一些SQL语句

2. 直接执行原生SQL语句

from django.db import connection

cursor = connection.cursor()

cursor.execute('select id from userinfo;')

cursor.fetchall()

3. 分组聚合

QuertySet.annotate()  --> 分组,前面查的是什么字段就按什么字段分组

QuertySet.aggregate() --> 聚合,给QuerySet中的每个对象多一个属性

4. 4合1路由

不同的路由可以使用同一个视图函数!!! --> 视图函数中通过参数的不同,实现不同的功能

5. 文章详情页

1. 母板继承

2. inclusion_tag

1. 返回一段HTML代码,用数据填充的HTML代码

2. 具体的写法

1. 在app下面创建一个名为 templatetags 的 Python Package

2. 在上面的包中创建一个 py文件

3. 按照inclusion_tag的格式要求写功能函数

from django import template

register = template.Library()

@register.inclusion_tag(file='xx.html')

def show_menu(*arg):

...

return {"k1": "v1"}

(xx.html中使用k1这个变量)

3. 点赞

1. ajax发送点赞的请求

1. 点赞必须是登录用户,没登录跳转到登录页面

2. 不能给自己的文章点赞

3. 一个用户只能给一篇文章点一次赞或踩一次

2. 后端创建点赞记录(事务操作)

1. 创建新的点赞记录

2. 去对应的文章表里把点赞数更新一个

3. ORM事务操作

from django.db import transaction

with transaction.atomic():

sql1;

sql2;

4. Django模板语言里面的JS代码

如何在js中引用模板语言的变量,注意加引号!!!

接下来就开始写评论区的功能了,首先就是在页面布局:

我们希望吧页面布局成这个样式:

3e982b6d518574bcaeaede4cc0735e97.png

在bootstrap找到样式之后,作相应的改动:我们先想一下,在这个区域需要哪些数据,首先就是评论发表的时间,评论的作者,还有评论的内容。所以在文章详情页面的试图函数中应该传一些comment的参数。之后再页面中,通过for循环,逐个展示评论:

评论
{% for comment in comment_list %}

#{{ forloop.counter }}楼

{{ comment.create_time|date:'Y-m-d H:i' }}

{{ comment.user.username }}

{{ comment.content }}

{% endfor %}

接下来就是发表评论的区域了:

6949448c940c186e46d407aa51e85387.png同样是先布局,然后html代码:

发表评论
昵称:

评论内容:

提交

接下来就是发送ajax请求了。

我们能够很容易的写出来这步:

//给评论按钮绑定点击事件

$('#submit-comment').click(function () {

var userid= '{{ request.user.id }}';

var articleid= '{{ article_obj.id }}';

var content= $('#new-comment').val();

var csrf_token= $('[name="csrfmiddlewaretoken"]').val();

$.ajax({

url:'/comment/',

type:'post',

data:{

user_id:userid,

article_id:articleid,

content:content,

csrfmiddlewaretoken:csrf_token,

},

success:function (res) {

console.log(res)

}

})

})

试图函数也可以这样写;

defcomment(request):if request.method == 'POST':

res= {'code':0}

user_id= request.POST.get('user_id')

article_id= request.POST.get('article_id')

content= request.POST.get('content')with transaction.atomic():

# 1.先去创建新评论

comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)

# 2.再去更新该文章的评论数

models.Article.objects.update(comment_count=F('comment_count')+1)

return JsonResponse(res)

这样基本的评论功能已经写出来了,给文章评论之后,刷新之后在页面上就能够展示出评论内容,

但是我们实际的评论不是这样的,当我们评论之后,评论内容就会马上出现在展示区,不用通过刷新。这一步怎么实现呢?

这就要求我们在发送请求成功之后的success函数中将它通过js操作展示出来,说白了就是在原来评论展示区的下面再添加一个展示区。所以试图函数要返回一些数据:

views.py代码:

defcomment(request):if request.method == 'POST':

res= {'code':0}

user_id= request.POST.get('user_id')

article_id= request.POST.get('article_id')

content= request.POST.get('content')with transaction.atomic():

# 1.先去创建新评论

comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)

# 2.再去更新该文章的评论数

models.Article.objects.update(comment_count=F('comment_count')+1)

res['data'] ={'id':comment_obj.id,'username':comment_obj.user.username,'content':comment_obj.content,'create_time':comment_obj.create_time.strftime("Y-m-d") # 这部如果看不懂的话就去复习一下那三种时间格式的相互转化 }return JsonResponse(res)

在说js操作代码之前,我们先来复习一个知识:就是js中的字符串格式化输出。

a652d41c1142b4536e6a31b8b4f5db9b.png

# 给评论按钮绑定点击事件

$('#submit-comment').click(function () {

var userid= '{{ request.user.id }}';

var articleid= '{{ article_obj.id }}';

var content= $('#new-comment').val();

var csrf_token= $('[name="csrfmiddlewaretoken"]').val();

$.ajax({

url:'/comment/',

type:'post',

data:{

user_id:userid,

article_id:articleid,

content:content,

csrfmiddlewaretoken:csrf_token,

},

success:function (res) {

console.log(res)if(res.code===0){

var data=res.data//先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一

var num= $('.comment-list>div').length + 1;//创建评论成功后,通过js在评论区列表在添加一条评论

var commenthtml=`

#${ num }楼

${ data.create_time }

${ data.username }

${ data.content }

`//在原来的评论列表后面添加一条

$('.comment-list').append(commenthtml)//情空 textarea

$('#new-comment').val('')

}

}

})

})

上面写的是添加父评论。

接下来添加子评论,就是回复的部分了:

博客园中当我们点击回复按钮时,评论区会显示这样:

分为两部:当我们点击回复标签时,光标就会聚焦在评论区,并且出现了@xxx

c7e80ffd47a94c07db2379dd79d37ddc.png这个如何实现呢?

$('.replay').click(function () {//光标聚焦在textarea//出现@xxx

var replayname= $(this).prev().text() //取到当前标签的前一个标签的文本

$('#new-comment').focus().val('@'+replayname+'\n')

})

comment表里有parent_comment字段,我们应该怎么取到这个字段的id呢?

当我们点击提交的时候,我们不管有没有父评论都给后端传一个parent_id,我们给评论的那个div加一个自定义的id

评论
{% for comment in comment_list %}

#{{ forloop.counter }}楼

{{ comment.create_time|date:'Y-m-d H:i' }}

{{ comment.user.username }}

{% if comment.parent_comment %}

@{{ comment.parent_comment.user.username }}

{{ comment.parent_comment.content }}

{% endif %}

{{ comment.content }}

{% endfor %}

那么我们如何区分谁是父评论谁是子评论呢?当我们点击回复的时候,产生的评论就是子评论,直接点击提交就是父评论,那我们应该怎么操作呢?

我们把这个自定义的id添加到提交的按钮上,当我们点击提交的按钮是进行判断,如果这个id存在,就说明是子评论,否则就是父评论。

//点击回复按钮时的绑定事件

$('.replay').click(function () {//光标聚焦在textarea//出现@xxx

var replayname= $(this).prev().text() ;//取到当前标签的前一个标签的文本

$('#new-comment').focus().val('@'+replayname+'\n');//把当前评论的id值,存到提交的按钮中

var pID= $(this).parent().parent().attr('my-id');

$('#submit-comment').data('pid',pID)

})

//给评论按钮绑定点击事件

$('#submit-comment').click(function () {

var userid= '{{ request.user.id }}';

var articleid= '{{ article_obj.id }}';

var content= $('#new-comment').val();

var csrf_token= $('[name="csrfmiddlewaretoken"]').val();

var parentId= $(this).data('pid') || '';if(parentId){

//因为在添加自评论时,会出现@xxx的东西所以我们按照索引把他去除

content= content.slice(content.indexOf('\n')+1,);

}

$.ajax({

url:'/comment/',

type:'post',

data:{

parent_id:parentId,

user_id:userid,

article_id:articleid,

content:content,

csrfmiddlewaretoken:csrf_token,

},

success:function (res) {

console.log(res)if(res.code===0){

var data=res.data//先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一

var num= $('.comment-list>div').length + 1;//创建评论成功后,通过js在评论区列表在添加一条评论

var commenthtml=`

#${ num }楼

${ data.create_time }

${ data.username }

${ data.content }

`;//在原来的评论列表后面添加一条

$('.comment-list').append(commenthtml);//情空 textarea

$('#new-comment').val('');

//当我们点击提交按钮时,应该把自定义的id去掉,不然下一次点击提交的时候,还是有这个id值

$("#submit-comment").removeData("pid");

}

}

})

});

我们后端也能拿到parent_id。

defcomment(request):if request.method == 'POST':

res= {'code':0}

user_id= request.POST.get('user_id')

article_id= request.POST.get('article_id')

content= request.POST.get('content')

parent_id= request.POST.get("parent_id")#创建评论

with transaction.atomic():#1.先去创建新评论

ifparent_id:#添加自评论

comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=parent_id)else:#添加父评论

comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)#2.再去更新该文章的评论数

models.Article.objects.update(comment_count=F('comment_count')+1)

res['data'] ={'parent_id':parent_id,'id':comment_obj.id,'username':comment_obj.user.username,'content':comment_obj.content,'create_time':comment_obj.create_time.strftime("Y-m-d")

}return JsonResponse(res)

这样添加的评论还不够完美,就是添加的评论没有回复这个功能,

//给评论按钮绑定点击事件

$('#submit-comment').click(function () {

var userid= '{{ request.user.id }}';

var articleid= '{{ article_obj.id }}';

var content= $('#new-comment').val();

var csrf_token= $('[name="csrfmiddlewaretoken"]').val();

var parentId= $(this).data('pid') || '';if(parentId){//因为在添加自评论时,会出现@xxx的东西所以我们按照索引把他去除

content= content.slice(content.indexOf('\n')+1,);

}

$.ajax({

url:'/comment/',

type:'post',

data:{

parent_id:parentId,

user_id:userid,

article_id:articleid,

content:content,

csrfmiddlewaretoken:csrf_token,

},

success:function (res) {

console.log(res)if(res.code===0){

var data=res.data//先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一

var num= $('.comment-list>div').length + 1;//创建评论成功后,通过js在评论区列表在添加一条评论

var commenthtml=`

#${ num }楼

${ data.create_time }

${ data.username }

回复

${ data.content }

`;//在原来的评论列表后面添加一条

$('.comment-list').append(commenthtml);//情空 textarea

$('#new-comment').val('');//当我们点击提交按钮时,应该把自定义的id去掉,不然下一次点击提交的时候,还是有这个id值

$("#submit-comment").removeData("pid");

}

}

})

});

添加回复这个按钮后,不能实现点击,这就用到了事件委托,当一个事件不能完成时,我们把它委托给他的父标签做将来的动作。

//给回复按钮绑定事件//$('.replay').click(function () {//事件委托,

$('.comment-list').on('click','.replay',function () {//光标聚焦在textarea//出现@xxx

var replayname= $(this).prev().text() ;//取到当前标签的前一个标签的文本

$('#new-comment').focus().val('@'+replayname+'\n');//把当前评论的id值,存到提交的按钮中

var pID= $(this).parent().parent().attr('my-id');

$('#submit-comment').data('pid',pID)

})

这就是完整的代码了

不懂得地方看视频,(看视频day79. 004)

上面设计到的知识点,jquery中的data方法,就是我们可以给任意一个jQuery对象添加一个值。

8d51aea364d25a520bd6233c4fef6d46.png

js中的三元运算:

6ea4e9a7af7941d8871ad66ab6237a9c.png

还有就是事件委托

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值