仿bbs项目之评论功能完善,后台管理功能部分讲解,bs4模块简介
仿bbs项目之评论功能完善,后台管理功能部分讲解,bs4模块简介
昨日内容回顾
-
个人站点侧边栏筛选功能
1.研究侧边栏路由规律 2.初步指定三个路由 站点名称\category\分类主键值 站点名称\tag\标签主键值 站点名称\archive\年-月 3.路由优化设计 正则匹配 4.由于筛选还是基于个人站点 所以多个路由使用相同的视图函数 通过视图函数接收的实参个数不同从而区分不同的业务逻辑 5.根据条件二次过滤文章数据 正反向查询、神奇的双下划线查询
-
侧边栏inclusion_tag制作
1.侧边栏很多页面都需要使用 并且还需要传参才可以加载出来 2.干脆制作成inclusion_tag调用 从而节省代码 3.自定义操作固定步骤(模板层相关知识)
-
点赞点踩样式搭建
直接拷贝博客园相关html和css即可 ps:图片防盗链技术
-
点赞点踩功能完善
1.前端页面给点赞点踩图标绑定点击事件 通过标签class值的不同区分是赞还是踩 发送ajax请求携带文章主键值、点赞点踩。。。 2.后端业务逻辑 校验用户是否登录、校验当前用户是否是文章作者、校验当前用户是否已经点过、完成数据库操作(注意普通字段(优化的评论数点赞点踩字段)数据更新) ps:注意前端发送过来的js类型的布尔值需要自己处理成python布尔值 3.前端展示优化 信息提示、数字动态变化 ps:针对标签文本需要做类型转换 否则默认是字符串拼接
-
文章评论样式搭建
最简易的几个标签 获取用户输入的textarea以及一个提交按钮
-
文章根评论业务逻辑
1.给提交按钮绑定点击事件 2.发送ajax请求 携带评论内容、文章主键 3.后端直接获取数据并写入数据库 还是得注意文章表中的普通字段 ps:很多业务逻辑可能需要执行多条ORM语句 这个时候稳了保证数据的完整可以采用事务操作(回想ORM事务的三种操作方式(全局事务、装饰器,with局部))
今日内容概要
- 根评论完善
- 子评论回复按钮功能
- 子评论功能完善
- 后台管理搭建
- 添加文章页面搭建
- 富文本编辑器
- 添加文章初步实现
- bs4模块简介
今日内容详细
根评论完善
提交评论
评论框里面的内容会清空 然后页面会有一个临时评论样式出现 页面刷新才会出现评论样式
先提前获取数据,方便使用
// 获取用户评论的内容
let commentMsg = $('#comment').val();
// 提前获取当前用户名字
let currentUserName = '{{ request.user.username }}'
当数据通过一系列校验并返回到ajax内时,清空评论框内容,查找ul标签并添加子标签(临时添加到评论楼,不影响刷新页面的展示)
'''
success: function (args) {
if(args.code === 10000){
// 清空评论框内容
$('#comment').val('');
// 动态创建标签并添加到评论楼中(临时评论楼)
let tempComment = `
<li class="list-group-item">
<span class="glyphicon glyphicon-comment"><a href="/${currentUserName}/">${currentUserName}</a></span>
<p>
${commentMsg}
</p>
</li>
`
// 查找ul标签动态添加子标签即可
$('.list-group').append(tempComment)
}
}
'''
研究子评论特性
每个评论右侧都应该有回复按钮 点击就可以填写子评论
点击回复按钮具体动作:评论框中自动添加@+评论人名并换行 聚焦
如何区分不同的回复按钮对应的用户名
利用标签可以自定义属性直接携带对应的评论用户名即可
<p class="pull-right"><a href="#" class="reply" username="{{ comment_obj.user.username }}">回复 </a></p>
username:当前评论用户名
'''
//给回复按钮绑定点击事件
$('.reply').click(function () {
let targetUserName = $(this).attr('username');
$('#comment').val('@' + targetUserName + '\n').focus()
})
'''
点击回复按钮发送子评论 页面不刷新的情况下 后续的评论全部成了子评论
原因是全局变量parentId没有清空导致的 每次提交评论都应该清空一下
'''
// 清空全局变量parentId使下一个评论不再绑定parentId
parentId = null;
'''
针对子评论内的@用户名换行 理论上不属于用户评论的内容 不应该记录到数据库
前端可以剔除 也可以在后端剔除
'''
前端:
// 如果发送的是子评论,则进行切割处理掉前缀内容
if(parentId){
commentMsg = commentMsg.slice(commentMsg.indexOf('\n') + 1)
}
后端:
判断parentId是否有值,有值则用split切割掉\n之后的内容即可
'''
针对子评论的渲染 应该动态判断是否是子评论 如果是应该加上评论的目标用户名
'''
在回复的后面添加p标签
<p>
{% if comment_obj.parent_id %}
@{{ comment_obj.parent.user.username }}
{% endif %}
</p>
'''
'''
因为临时渲染的评论之前被切割用于后端的使用,再用变量名接收一下没切割之前的评论,用作临时渲染评论
// 获取没处理之前的子评论
old_commentMsg = commentMsg;
'''
ps:针对评论的渲染也可以分页 也可以做根评论与子评论的集合操作(分类)(楼中楼)
后台管理
1.模仿博客园后台访问直接展示所有文章
2.后台管理页面需要多次被当作模板页面使用 如果该页面也是继承其他页面那么无法二次被继承使用 所以我们单独编写一个后台管理的模板页面、
'''
继承home页面
1.路由
# 后台管理接口
path('backend/', views.backend_func),
2.视图
@login_required
def backend_func(request):
site_obj = models.Site.objects.filter(site_name=request.user.username).first()
# 获取当前站点下所有的文章
article_queryset = models.Article.objects.filter(site=site_obj)
'''文章过多的情况下应该考虑添加分页器'''
page_obj = myPage.Pagination(current_page=request.GET.get('page'), all_count=article_queryset.count())
page_queryset = article_queryset[page_obj.start:page_obj.end]
return render(request, 'backend/backend.html', locals())
3.前端直接找样式,然后写table表单和分页器
<table class="table table-hover table-striped">
<thead>
<tr>
<th>标题</th>
<th>时间</th>
<th>评论数</th>
<th>点赞数</th>
<th>点踩数</th>
<th>操作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for article_obj in page_queryset %}
<tr>
<td><a href="/{{ site_obj.site_name }}/article/{{ article_obj.pk }}">{{ article_obj.title }}</a></td>
<td>{{ article_obj.create_time|date:'Y-m-d H:i:s' }}</td>
<td>{{ article_obj.comment_num }}</td>
<td>{{ article_obj.up_num }}</td>
<td>{{ article_obj.down_num }}</td>
<td><a href="#">编辑</a></td>
<td><a href="#">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{{ page_obj.page_html|safe }}
'''
添加文章
1.页面简易搭建
'''
1.路由
# 后台管理之添加文章接口
path('add_article/', views.add_article_func),
2.视图
@login_required
def add_article_func(request):
# 当前站点样式需要当前站点的对象
site_obj = models.Site.objects.filter(site_name=request.user.username).first()
category_list = models.Category.objects.filter(site=site_obj)
tag_list = models.Tag.objects.filter(site=site_obj)
return render(request, 'backend/addArticlePage.html', locals())
3.前端
<h2 class="text-center">添加文章</h2>
<form action="" method="post">
{% csrf_token %}
<p>文章标题</p>
<input type="text" name="title" class="form-control">
<p>文章内容</p>
<textarea name="content" id="" cols="30" rows="10" class="form-control"></textarea>
<p>文章分类</p>
<p>
{% for category_obj in category_list %}
<input type="radio" name="category" value="{{ category_obj.pk }}">{{ category_obj.name }}
{% endfor %}
</p>
<p>文章标签</p>
<p>
{% for tag_obj in tag_list %}
<input type="checkbox" name="tag" value="{{ tag_obj.pk }}">{{ tag_obj.name }}
{% endfor %}
</p>
<input type="submit" class="form-control btn btn-block btn-success">
</form>
'''
2.文章内容区富文本编辑器的使用
1.先下载kindeditor富文本编辑器,添加到static静态文件中
2.js区根据id值导入样式即可
'''
<script charset="utf-8" src="/static/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="/static/kindeditor/lang/zh-CN.js"></script>
<script>
KindEditor.ready(function (K) {
window.editor = K.create('#mycontent',
{
width : '100%',
height : '300px',
}
);
});
</script>
'''
3.添加文章具体业务代码
'''
# 根据post请求获取用户输入数据
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
category_id = request.POST.get('category')
tag_list = request.POST.get('tag')
# 操作文章表写入数据
article_obj = models.Article.objects.create(
title=title,
desc=content[1:150],
content=content,
site=site_obj,
category_id=category_id,
)
# 因为文章标签与文章多对多 第三张表 自己去操作第三张表
for tag_id in tag_list:
models.Article2Tag.objects.create(article=article_obj, tag_id=tag_id)
return redirect('/backend/')
'''
3.添加文章需要注意的问题
文章简介不应该有标签存在
文章内容不允许编辑script脚本(XSS攻击)
涉及到html相关内容的处理 可以借助于爬虫相关模块
bs4