BBS项目 day05 后台系统功能(首页、文章列表展示、添加文章、上传文件(uuid生成新的文件名))

阅读: 评论:0

BBS项目 day05 后台系统功能(首页、文章列表展示、添加文章、上传文件(uuid生成新的文件名))

BBS项目 day05 后台系统功能(首页、文章列表展示、添加文章、上传文件(uuid生成新的文件名))

一、后台功能的初始配置

1. urls.py路由分发

    re_path('app02/', include('app02.urls')),

2.app02/urls.py

from django.urls import path, re_path, include
from app02 import viewsurlpatterns = [path('home/', views.home),path('article_list/', views.article_list),path('add_article/', views.add_article),path('upload_image/', views.upload_image),
]

二、后台功能之首页

1.首页前端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>{% load static %}<script src="{% static 'js/jquery.min.js' %}"></script><link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet"><script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script><script src="{% static 'layer/layer.js' %}"></script></head>
<body>{# 导航条开始 #}
<nav class="navbar navbar-inverse"><div class="container-fluid"><!-- Brand and toggle get grouped for better mobile display --><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse"data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="#">BBS博客园后台系统</a></div><!-- Collect the nav links, forms, and other content for toggling --><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li><li><a href="#">分类</a></li><li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"aria-expanded="false">点我看更多美女哦 <span class="caret"></span></a><ul class="dropdown-menu"><li><a href="#">Action</a></li><li><a href="#">Another action</a></li><li><a href="#">Something else here</a></li><li role="separator" class="divider"></li><li><a href="#">Separated link</a></li><li role="separator" class="divider"></li><li><a href="#">One more separated link</a></li></ul></li></ul><form class="navbar-form navbar-left"><div class="form-group"><input type="text" class="form-control" placeholder="Search"></div><button type="submit" class="btn btn-default">搜索</button></form><ul class="nav navbar-nav navbar-right">{% if request.session.username %}<li style="line-height: 50px;"><!-- /media/{ article.blog.userinfo.avatar }} -->{# <img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" style="width: 100px;" alt="..."> #}<img src="/media/{{ cur_avatar }}" style="width: 50px; height: 36px;" class="onImg" alt=""></li><li><a href="#">{{ request.session.username }}</a></li><li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"aria-expanded="false">更多操作 <span class="caret"></span></a><ul class="dropdown-menu"><li><a href="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li><li><a href="#">更改头像</a></li><li><a href="/logout/">退出登录</a></li><li><a href="#">后台管理</a></li></ul></li>{% else %}<li><a href="/login/">登录</a></li><li><a href="/register/">注册</a></li>{% endif %}</ul><!-- 模态框 --><div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"><div class="modal-dialog modal-lg" role="document"><div class="modal-content"><div class="row"><h1 class="text-center">修改密码</h1><div class="col-md-8 col-md-offset-2"><div class="form-group">用户名:<input type="text" readonly value="{{ request.session.username }}"class="form-control"></div><div class="form-group">原密码:<input type="password" id="old_password" class="form-control" msg="原密码必须输入"></div><div class="form-group">新密码:<input type="password" id="new_password" class="form-control" msg="原密码必须输入"></div><div class="form-group">确认密码:<input type="password" id="re_password" class="form-control" msg="原密码必须输入"></div><div class="form-group"><input type="button" value="修改密码" class="btn btn-primary btn-block btn_password"></div></div></div></div></div></div></div><!-- /.navbar-collapse --></div><!-- /.container-fluid -->
</nav>
{# 导航条结束 #}<div class="container-fluid"><div class="row"><div class="col-md-3"><div class="list-group"><a href="#" class="list-group-item active">首页</a><a href="/app02/article_list/" class="list-group-item">文章列表</a><a href="#" class="list-group-item">分类类别</a><a href="#" class="list-group-item">标签列表</a><a href="#" class="list-group-item">更多</a></div></div><div class="col-md-9"><div class="panel panel-info"><div class="panel-heading">我自一口真气足</div><div class="panel-body">{% block content %}<div class="jumbotron"><h1>最牛叉的博客平台</h1><p>无招胜有招</p><p><a class="btn btn-primary btn-lg" href="#" role="button">更过风景</a></p></div><div class="row"><div class="col-sm-6 col-md-4"><div class="thumbnail"><img src="=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"alt="..."><div class="caption"><h3>Thumbnail label</h3><p>清风拂山岗</p><p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"class="btn btn-default"role="button">如来神掌</a></p></div></div></div><div class="col-sm-6 col-md-4"><div class="thumbnail"><img src="=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"alt="..."><div class="caption"><h3>Thumbnail label</h3><p>清风拂山岗</p><p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"class="btn btn-default"role="button">如来神掌</a></p></div></div></div><div class="col-sm-6 col-md-4"><div class="thumbnail"><img src="=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"alt="..."><div class="caption"><h3>Thumbnail label</h3><p>清风拂山岗</p><p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"class="btn btn-default"role="button">如来神掌</a></p></div></div></div></div>{% endblock %}</div></div></div></div>
</div>{% block js %}{% endblock %}</body>
</html>

2.首页后端

def home(request):return render(request, 'backend/home.html', locals())

三、后台功能之文章列表展示

1.文章列表展示前端

{% extends 'backend/home.html' %}{% block content %}<h2 class="text-center">文章列表</h2><form action=""><div class="form-group">文章标题<input type="text" id="title" class="form-control"></div><div class="form-group">文章分类<select name="" id="cate" class="form-control">{% for cate in cate_list %}<option value="{{ cate.pk }}">{{ cate.name }}</option>{% endfor %}</select></div><div class="form-group"><p>文章标签</p>{% for tags in tags_list %}{{ tags.name }}&nbsp;<input type="checkbox" value="{{ tags.pk }}" name="tags">&nbsp;&nbsp;{% endfor %}</div><div class="form-group">文章内容<textarea id="editor_id" name="content" style="width:100%;height:300px;"></textarea></div><div class="form-group"><input type="button" id="title" value="提交" class="btn btn-success btn-block btn_article"></div></form>{% endblock %}{% block js %}<script charset="utf-8" src="/static/kindeditor/kindeditor-all.js"></script><script charset="utf-8" src="/static/kindeditor/lang/zh-CN.js"></script><script&ady(function (K) {window.editor = K.create('#editor_id', {height: '500px',items: ['source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste','plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright','justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript','superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/','formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold','italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage','flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak','anchor', 'link', 'unlink', '|', 'about'],colorTable: [['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'],['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'],['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'],['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000']],resizeType: 0, // 0,1,2uploadJson : '/app02/upload_image/',extraFileUploadParams : {csrfmiddlewaretoken: '{{ csrf_token }}'},});});$(".btn_article").click(function () {// 接收参数// 标题let title = $("#title").val();//分类let cate_id = $("#cate").val();// 标签:由于是复选框,所以有可能有多个值的情况,需用循环取值// 定义一个数组,用于接收tags的值tags_arr = []var tags = $("input[name='tags']:checked");$.each(tags, function (index, value) {console.log(index, $(this).val());// 将复选框的值放入数组中tags_arr.push($(this).val());});console.log(tags_arr); // [3, 4]// 注意:由于这里的值是数组,在后端获取不到,需要转为字符串才能传给后端获取// 数组转字符串 joinvar tags_str = tags_arr.join(',')  // 3, 4console.log(tags_str);// 内容// 同步数据后可以直接取得textarea的valueeditor.sync();content = $('#editor_id').val(); // jQueryconsole.log(content)// 发起Ajax请求$.ajax({url: '',type: 'post',data: {title: title,cate_id: cate_id,tags: tags_str,content: content,csrfmiddlewaretoken: '{{ csrf_token }}',},success: function (res) {if (de === 200) {layer.msg(res.msg, {} ,function () {location.href = '/app02/article_list/'});} else {layer.msg(res.msg, {});}}});});</script>
{% endblock %}

2.文章列表后端

def article_list(request):# 查询出所有的文章列表articles_list = models.Article.objects.all()return render(request, 'backend/article_list.html', locals())

三、后台功能之添加文章

1.添加文章前端

{% extends 'backend/home.html' %}{% block content %}<h3 class="text-center">添加文章</h3><form action=""><div class="form-group">文章标题:<input type="text" id="title" class="form-control"></div><div class="form-group">文章分类:<select name="" id="cate" class="form-control">{% for category in category_list %}<option value="{{ category.pk }}">{{ category.name }}</option>{% endfor %}</select></div><div class="form-group"><p>文章标签:</p>{% for tags in tags_list %}{{ tags.name }}&nbsp;<input type="checkbox" id="title" name="tags" value="{{ tags.pk }}" style="margin-right: 10px;">{% endfor %}</div><div class="form-group">文章内容:<textarea id="editor_id" name="content" style="width:100%;height:400px;"></textarea></div><div class="form-group"><!-- type="submit" 会自动提交表单 --><!-- <button></button> 会自动提交表单,注意:当写在外面的时候才不会自动提交form表单 -->{# <input type="submit" value="提交" id="title" class="btn btn-success btn-block"> #}<!-- type="button" 不会自动提交表单 --><input type="button" value="提交" id="title" class="btn btn-success btn-block btn_article"></div></form>{% endblock %}

2.添加文章后端

def add_article(request):# 文本编辑器官网 .phpuser_obj = models.UserInfo.objects.filter(pk=('id')).first()if not user_obj:return redirect('/login/')blog = user_obj.blog# 查询所有的分类category_list = models.Category.objects.all()# 查询所有的标签列表tags_list = models.Tag.objects.all()back_dict = {'code': 200, 'msg': '添加成功', 'data': []}# 1.获取前段传递过来的数据hod == 'POST':title = ('title')cate_id = ('cate_id')content = ('content')tags = ('tags')  # 1, 2# tags原本是一个列表,但是前端传值时进行了转换,有列表转为了字符串# 在此,要先转位列表去使用tags_list = tags.split(',')  # [1, 2]# 2.参数验证if not title:back_dict['code'] = 1500back_dict['msg'] = '标题必须有'return JsonResponse(back_dict)if not cate_id:back_dict['code'] = 1501back_dict['msg'] = '分类必须选择'return JsonResponse(back_dict)if not tags:back_dict['code'] = 1502back_dict['msg'] = '标签必须选择'return JsonResponse(back_dict)if not content:back_dict['code'] = 1503back_dict['msg'] = '内容不能为空'return JsonResponse(back_dict)'''1.摘要截取的问题2.xss攻击的问题----->原理:有了script标签------>把提交过来的内容过滤出script标签,然后做删除解决方法:1.使用正则匹配 script,匹配到之后,做删除,这个方法很麻烦,不推荐2.利用第三方模块来处理:bs4模块pip install bs4BeautifulSoup它是用在爬虫里面,它能够筛选数据,清晰html数据BeautifulSoup('', 'html.parser')使用lxml的话需要安装 pip install lxmlBeautifulSoup('', 'lxml')'''# 解决xss攻击的问题from bs4 import BeautifulSoupsoup = BeautifulSoup(content, 'html.parser')# print(soup.find_all('a'))  # 写的a那么久就筛选a# print(soup.find_all('script'))# )  # 打印文本内容for tag in soup.find_all():# print(tag.name)if tag.name == 'script':# 删除scripttag.decompose()# 文章摘要直接从内容中截取 100字desc = [:100]# 3.数据入库,需要操作文章表,文章、标签的第三张表article_obj = models.ate(title=title, content=str(soup), desc=desc, category_id=cate_id,blog=blog)# 操作标签的第三张表,数据是多对多,选择批量插入数据article_tag_list = []for i in tags_list:article_tag_obj = models.Article2Tag(article_id=article_obj.pk, tag_id=i)article_tag_list.append(article_tag_obj)models.Article2Tag.objects.bulk_create(article_tag_list)return JsonResponse(back_dict)return render(request, 'backend/add_article.html', locals())

四、后台功能之上传文件

1.添加文章前端

{% extends 'backend/home.html' %}{% block content %}<h3 class="text-center">添加文章</h3><form action=""><div class="form-group">文章标题:<input type="text" id="title" class="form-control"></div><div class="form-group">文章分类:<select name="" id="cate" class="form-control">{% for category in category_list %}<option value="{{ category.pk }}">{{ category.name }}</option>{% endfor %}</select></div><div class="form-group"><p>文章标签:</p>{% for tags in tags_list %}{{ tags.name }}&nbsp;<input type="checkbox" id="title" name="tags" value="{{ tags.pk }}" style="margin-right: 10px;">{% endfor %}</div><div class="form-group">文章内容:<textarea id="editor_id" name="content" style="width:100%;height:400px;"></textarea></div><div class="form-group"><!-- type="submit" 会自动提交表单 --><!-- <button></button> 会自动提交表单,注意:当写在外面的时候才不会自动提交form表单 -->{# <input type="submit" value="提交" id="title" class="btn btn-success btn-block"> #}<!-- type="button" 不会自动提交表单 --><input type="button" value="提交" id="title" class="btn btn-success btn-block btn_article"></div></form>{% endblock %}{% block js %}{% load static %}<script charset="utf-8" src="{% static 'kindeditor/kindeditor-all.js' %}"></script><script charset="utf-8" src="{% static 'kindeditor/lang/zh-CN.js' %}"></script><script&ady(function (K) {window.editor = K.create('#editor_id', {height: '300px',items: ['source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste','plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright','justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript','superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/','formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold','italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage','flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak','anchor', 'link', 'unlink', '|', 'about'],resizeType: 0,colorTable: [['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'],['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'],['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'],['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'],],uploadJson: '/upload_image/',extraFileUploadParams: {csrfmiddlewaretoken: '{{ csrf_token }}'},});});// 绑定点击事件$(".btn_article").click(function () {// 同步数据后可以直接取得textarea的valueeditor.sync();// 获取数据// 标题let title = $("#title").val();// 分类let cate = $("#cate").val();// 文章标签是复选框,所以通过属性选择器获取值,// 由于是复选框的缘故,可能会有多个值的情况出现,所以应该循环取值// 注意:获取复选框时,不要加上 .val(),循环取值的再加上let tags = $("input[name='tags']:checkbox");let tags_arr = []$.each(tags, function (index, value) {tags_arr.push($(this).val());});console.log(tags_arr); // [1,2,3,4]// 由于是数组,所以传递到后台的数据不是字符串,要先转为字符串// 在下面的Ajax的 data 中传值也要传递字符串var tags_str = tags_arr.join(',');console.log(tags_str);// 内容{#html = ElementById('editor_id').value; // 原生API#}{#html = K('#editor_id').val(); // KindEditor Node API#}let content = $("#editor_id").val(); // jQueryconsole.log(content);// 发起Ajax请求$.ajax({url: '',type: 'post',data: {title: title,cate: cate,tags: tags_str,content: content,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {if (code === 200) {layer.msg(res.msg, {}, function () {location.href = '/app02/article_list/';});} else {layer.msg(res.msg, {});}}});});</script>
{% endblock %}

2.添加文章后端

# 上传图片
def upload_image(request):'''返回格式:josn//成功时{"error" : 0,"url" : ".ext"}//失败时{"error" : 1,"message" : "错误信息"}'''# 方式1:hod == 'POST':file_obj = ('imgFile')# print(file_obj)  # <MultiValueDict: {'imgFile': [<InMemoryUploadedFile: 7.jpg (image/jpeg)>]}># 拼接上传文件的路径import f import settings# /media/article_img/xx.123.pngBASE_DIE = os.path.join(settings.BASE_DIR, 'media', 'article_img')file_name = os.path.join(BASE_DIE, file_obj.name)with open(file_name, 'wb') as f:for line in file_obj:f.write(line)# return HttpResponse('OK')return JsonResponse({"error": 0,"url": "/media/article_img/%s" % file_obj.name})# 方式2:将文件名用uuid随机生成重命名# 生成新的文件名import uuidnew_str = str(uuid.uuid4())new_uuid = place('-', '')new_file_name = new_uuid + '.' + file_obj.name.rsplit('.')[-1]new_file = os.path.join(BASE_DIE, new_file_name)with open(new_file, 'wb') as f:for line in file_obj:f.write(line)return JsonResponse({"error": 0,"url": "/media/article_img/%s" % new_file_name})

本文发布于:2024-02-04 08:32:51,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170703178053987.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23