BBS项目增加编辑文章功能
文章增加和编辑功能要点:
- 半自动多对多关系表的增改操作
- 基于bs4模块防御xss攻击
- 富文本编辑器的使用
由于文章表和标签表的多对多关系使用了半自动的创建方式,此时虽然可以使用ORM的跨表查询API,但是在新增记录或者修改记录时需要我们手动同时操作或更新两张表。此时最好使用事物,保证同时操作两张表。
另外,由于标签可能有多个,此时操作第三张关系表时,可能需要写入多个记录。这是最好使用orm的批量插入数据功能,避免频繁的操作数据库。
# 以编辑为例的视图函数,因为编辑操作第三张表稍微复杂点,
@method_decorator(login_required)
def post(self, request, article_id):
form_obj = myforms.ArticleEditForm(request.POST)
category_list = models.Category.objects.filter(blog=request.user.blog)
tag_list = models.Tag.objects.filter(blog=request.user.blog)
if form_obj.is_valid():
title = form_obj.cleaned_data.get('title')
content = form_obj.cleaned_data.get('content')
# 基于bs4模块防御xss攻击
soup = pre_xss(content)
category = request.POST.get('category')
tag_id_list = request.POST.getlist('tag')
with transaction.atomic():
models.Article.objects.filter(pk=article_id).\
update(title=title, content=str(soup), desc=soup.text[0:150], category_id=category)
# 先删除关系
models.Article2Tag.objects.filter(article_id=article_id).delete()
# 再批量增加关系
tag_tmp_list = (models.Article2Tag(article_id=article_id, tag_id=tag) for tag in tag_id_list)
models.Article2Tag.objects.bulk_create(tag_tmp_list)
return redirect('backend')
return render(request, 'backend/article_edit.html', locals())
xss攻击指的是在可以输入html内容的输入框中,用户可能通过输入js代码攻击网站服务器。这是的一个解决办法就是筛选出输入内容中的script标签的内容并删除之,这里我们直接使用bs4模块帮我们做这件事。
from bs4 import BeautifulSoup
def pre_xss(content):
soup = BeautifulSoup(content, 'html.parser')
tags = soup.find_all()
for tag in tags: # 获取所有的标签
if tag.name == 'script':
tag.decompose() # 针对script标签 直接删除
return soup
富文本编辑器我们使用的是KindEditor
,作为一个第三方工具,我们学习使用的使用一定要仔细阅读官网文档教程。
这里记录下使用的注意点:
- 官网下在代码,引入到html文件中
- 需要绑定textarea的id值
- 上传图片时,需要自己书写上传图片的方法:url、视图、以及视图返回的响应格式等
{% load static %}
<script charset="utf-8" src="{% static '/kindeditor/kindeditor-all-min.js' %}"></script>
<script>
KindEditor.ready(function(K) {
window.editor = K.create('#id_content', # textarea的id
{
width : '100%',
height: '500px',
resizeType: 1, # 仅高度可变
uploadJson : '{% url "upload_img" %}', // 朝后端该url提交上传文件的请求
extraFileUploadParams : {
'csrfmiddlewaretoken': '{{ csrf_token }}'
}
}
);
});
</script>
自己书写后端视图,上文的图片也应该保存在media中,需要自己拼接路径
@login_required
def upload_img(request):
back_info = {"error": 0}
file_obj = request.FILES.get('imgFile')
file_naw_path, file_new_name = save_image(file_obj)
back_info['url'] = f'/media/images/{file_new_name}/'
return JsonResponse(back_info)