BBS后台页搭建、富文本编辑上传文件、XSS攻击、修改头像
# 后台管理所有文件夹都可以根据功能再细化,你还可以继续创建文件夹分类处理
templates文件夹
backend文件夹
应用1文件夹
应用2文件夹
第一步是实现: 1、在static文件夹下单独创建一个backend文件夹统一管理关于后台的html页面 2、分为base.html,backend.html、add_article.html继承base做修改,
接下来看主要的base.html代码,因为很多地方要用到这个公共的模板<div class="container-fluid">
<div class="row">
<div class="col-md-2"> <div class="col-md-10">
div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">文章</a></li>
<li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">随笔</a></li>
<li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">文件</a></li>
<li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">设置</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="home">
{% block article %}
文章界面
{% endblock %}
</div>
<div role="tabpanel" class="tab-pane" id="profile">
{% block suibi %}
随笔界面
{% endblock %}
</div>
<div role="tabpanel" class="tab-pane" id="messages">
{% block file %}
文件界面
{% endblock %}
</div>
<div role="tabpanel" class="tab-pane" id="settings">
{% block set %}
设置界面
{% endblock %}
</div>
</div>
2、 backend.html管理页怎么搭建(继承base.html修改内容部分){% extends 'backend/backend_base.html' %}
{% block article %}
{# 展示当前用户所有的文章#}
<table class="table table-hover table-striped">
<thead>
<tr>
<th>标题</th>
<th>点赞数</th>
<th>评论数</th>
<th>操作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for article in page_queryset %}
<tr>
<td><a href="/{{ article.blog.userinfo.username }}/article/{{ article.pk }}/">{{ article.title }}</a></td>
<td>{{ article.up_num }}</td>
<td>{{ article.comment_num }}</td>
<td><a href="">编辑</a></td>
<td><a href="">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pull-right">
{{ page_obj.page_html|safe }}
</div>
{% endblock %}
</div>
from app01.utils.mypage import Pagination
@login_required
def backend(request):
# 获取当前用户对象所有的文章展示到页面
article_list = models.Article.objects.filter(blog=request.user.blog)
page_obj = Pagination(current_page=request.GET.get('page',1),all_count=article_list.count())
page_queryset = article_list
return render(request,'backend/backend.html',locals())
第二步:如何是富文本编辑器和文章的添加、防止XSS攻击</div>add_article.html搭建{% extends 'backend/backend_base.html' %}
{% block article %}
<h3>添加文章</h3>
{# 直接利用form表单提交数据#}
<form action="" method="post">
{% csrf_token %}
<p>标题</p>
<div>
<input type="text" name="title" class="form-control">
</div>
<p>内容</p>
<div>
<textarea name="content" id="id_content" cols="30" rows="10"></textarea>
</div>
<p>分类</p>
<div>
{% for category in category_list %}
<input type="radio" value="{{ category.pk }}" name="category">{{ category.name }}
{% endfor %}
</div>
<p>标签</p>
<div>
{% for tag in tag_list %}
<input type="checkbox" value="{{ tag.pk }}" name="tag">{{ tag.name }}
{% endfor %}
</div>
<input type="submit" class="btn btn-danger">
</form>
{% endblock %}
{% block js %}
{% 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', {
width: '100%',
height: '600px',
resizeType:1,
uploadJson : '/upload_image/',// 上传图片的后端提交路径
extraFileUploadParams : {
'csrfmiddlewaretoken':'{{ csrf_token }}'
}
});
});
</script>
{% endblock %}
[后端代码]关于添加文章、XSS攻击的from bs4 import BeautifulSoup
@login_required
def add_article(request):
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
category_id = request.POST.get("category")
tag_id_list = request.POST.getlist('tag')
# 模块使用
soup = BeautifulSoup(content,'html.parser')
tags = soup.find_all()
# 获取所有的标签
for tag in tags:
# print(tag.name)# 获取页面所有的标签
# 针对script标签 直接删除
if tag.name == 'script':
# 删除标签
tag.decompose()
# 文章简介
# 1 先简单暴力的直接切去content 150个字符
# desc = content
# 2 截取文本150个
desc = soup.text[0:150]
article_obj = models.Article.objects.create(
title=title,
content=str(soup),
desc=desc,
category_id=category_id,
blog=request.user.blog
)
# 文章和标签的关系表 是我们自己创建的 没法使用add set remove clear方法
# 自己去操作关系表 一次性可能需要创建多条数据 批量插入bulk_create()
article_obj_list = []
for i in tag_id_list:
tag_article_obj = models.Article2Tag(article=article_obj,tag_id=i)
article_obj_list.append(tag_article_obj)
# 批量插入数据
models.Article2Tag.objects.bulk_create(article_obj_list)
# 跳转到后台管理文章展示页
return redirect('/backend/')
category_list = models.Category.objects.filter(blog=request.user.blog)
tag_list = models.Tag.objects.filter(blog=request.user.blog)
return render(request,'backend/add_article.html',locals())关于传文件(图片)格式存储和接口处理import os
from BBS14 import settings
def upload_image(request):
"""
//成功时
{
"error" : 0,
"url" : "http://www.example.com/path/to/file.ext"
}
//失败时
{
"error" : 1,
"message" : "错误信息"
}
:param request:
:return:
"""
back_dic = {'error': 0, }# 先提前定义返回给编辑器的数据格式
# 用户写文章上传的图片 也算静态资源 也应该防盗media文件夹下
if request.method == "POST":
# 获取用户上传的图片对象
# print(request.FILES)# 打印看到了健固定叫imgFile
file_obj = request.FILES.get('imgFile')
# 手动拼接存储文件的路径
file_dir = os.path.join(settings.BASE_DIR,'media','article_img')
# 优化操作 先判断当前文件夹是否存在 不存在 自动创建
if not os.path.isdir(file_dir):
os.mkdir(file_dir)# 创建一层目录结构article_img
# 拼接图片的完整路径
file_path = os.path.join(file_dir,file_obj.name)
with open(file_path,'wb') as f:
for line in file_obj:
f.write(line)
back_dic['url'] = '/media/article_img/%s'%file_obj.name
return JsonResponse(back_dic)
第三步:修改头像> 前端代码{% extends 'base.html' %}
{% block content %}
<h3 class="text-center">修改头像</h3>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>
原头像:
<img src="/media/{{ request.user.avatar }}" alt="">
</p>
<p>
<label for="myfile">新头像:
{% load static %}
<img src="{% static 'img/default.png' %}" id='myimg' alt="" width="100" style="margin-left: 10px">
</label>
<input type="file" id="myfile" name="avatar" style="display: none" >
</p>
<input type="submit" class="btn btn-info">
</form>
{% endblock %}
{% block js %}
<script>
$("#myfile").change(function () {
// 文件阅读器对象
// 1 先生成一个文件阅读器对象
let myFileReaderObj = new FileReader();
// 2 获取用户上传的头像文件
let fileObj = $(this)[0].files[0];
// 3 将文件对象交给阅读器对象读取
myFileReaderObj.readAsDataURL(fileObj)// 异步操作IO操作
// 4 利用文件阅读器将文件展示到前端页面修改src属性
// 等待文件阅读器加载完毕之后再执行
myFileReaderObj.onload = function(){
$('#myimg').attr('src',myFileReaderObj.result)
}
})
</script>
{% endblock %}
后端代码@login_required
def set_avatar(request):
if request.method == 'POST':
file_obj = request.FILES.get('avatar')
# models.UserInfo.objects.filter(pk=request.user.pk).update(avatar=file_obj)# 不会再自动加avatar前缀
# 1.自己手动加前缀
# 2.换一种更新方式
user_obj = request.user
user_obj.avatar = file_obj
user_obj.save()
return redirect('/home/')
blog = request.user.blog
username = request.user.username
return render(request,'set_avatar.html',locals())
# bbs项目总结
在开发任意的web项目的时候 其实到了后期需要写的代码会越来越少
都是用已经写好的url填写到a标签href属性完成跳转即可
[主要功能总结]
1、表设计 开发流程(粗糙流程。还可以细化)
2、注册功能
form组件使用
头像动态展示
错误信息提示
3、登录功能
图片验证码
滑动验证码
4、首页展示
media配置
主动暴露任意资源接口
5、个人站点展示
侧边栏展示
侧边栏筛选
侧边栏inclusion_tag制作
6、文章详情页
点赞点踩
根评论、子评论
7、后台管理
[针对bbs需要你掌握每一个功能的书写思路和内部逻辑,之后再去敲代码熟悉找感觉]
页:
[1]