一、后台功能的初始配置
1. urls.py路由分发
re_path('app02/', include('app02.urls')),
2.app02/urls.py
from django.urls import path, re_path, include
from app02 import views
urlpatterns = [
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>Titletitle>
{% 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">
<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 navigationspan>
<span class="icon-bar">span>
<span class="icon-bar">span>
<span class="icon-bar">span>
button>
<a class="navbar-brand" href="#">BBS博客园后台系统a>
div>
<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="#">Actiona>li>
<li><a href="#">Another actiona>li>
<li><a href="#">Something else herea>li>
<li role="separator" class="divider">li>
<li><a href="#">Separated linka>li>
<li role="separator" class="divider">li>
<li><a href="#">One more separated linka>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;">
{# <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>
div>
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="https://img2.baidu.com/it/u=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"
alt="...">
<div class="caption">
<h3>Thumbnail labelh3>
<p>清风拂山岗p>
<p><a href="#" class="btn btn-primary" role="button">Buttona> <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="https://img2.baidu.com/it/u=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"
alt="...">
<div class="caption">
<h3>Thumbnail labelh3>
<p>清风拂山岗p>
<p><a href="#" class="btn btn-primary" role="button">Buttona> <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="https://img2.baidu.com/it/u=3323311628,2330835932&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1692464400&t=3cf590e7ea88465e48ef5170f7c70884"
alt="...">
<div class="caption">
<h3>Thumbnail labelh3>
<p>清风拂山岗p>
<p><a href="#" class="btn btn-primary" role="button">Buttona> <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 %}
<h3 class="text-center">文章列表</h3>
<a href="/app02/add_article" class="btn btn-success" style="margin-bottom: 10px">添加文章</a>
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>标题</th>
<th>点赞数</th>
<th>点踩数</th>
<th>评论数</th>
<th>更多</th>
</tr>
</thead>
<tbody>
{% for articles in articles_list %}
<tr>
<td><a href="/{{ request.session.username }}/{{ articles.pk }}" target="_blank">{{ articles.title }}</a></td>
<td>{{ articles.up_num }}</td>
<td>{{ articles.down_num }}</td>
<td>{{ articles.comment_num }}</td>
<td>
<a href="" class="btn btn-success">修改</a>
<a href="" class="btn btn-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% 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 }}
<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>
$(".btn_article").click(function () {
editor.sync();
let title = $("#title").val();
let cate = $("#cate").val();
let tags = $("input[name='tags']:checkbox");
let tags_arr = []
$.each(tags, function (index, value) {
tags_arr.push($(this).val());
});
console.log(tags_arr);
var tags_str = tags_arr.join(',');
console.log(tags_str);
{#html = document.getElementById('editor_id').value;
{#html = K('#editor_id').val();
let content = $("#editor_id").val();
console.log(content);
$.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 add_article(request):
user_obj = models.UserInfo.objects.filter(pk=request.session.get('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': []}
if request.method == 'POST':
title = request.POST.get('title')
cate_id = request.POST.get('cate_id')
content = request.POST.get('content')
tags = request.POST.get('tags')
tags_list = tags.split(',')
if not title:
back_dict['code'] = 1500
back_dict['msg'] = '标题必须有'
return JsonResponse(back_dict)
if not cate_id:
back_dict['code'] = 1501
back_dict['msg'] = '分类必须选择'
return JsonResponse(back_dict)
if not tags:
back_dict['code'] = 1502
back_dict['msg'] = '标签必须选择'
return JsonResponse(back_dict)
if not content:
back_dict['code'] = 1503
back_dict['msg'] = '内容不能为空'
return JsonResponse(back_dict)
'''
1.摘要截取的问题
2.xss攻击的问题----->原理:有了script标签------>把提交过来的内容过滤出script标签,然后做删除
解决方法:
1.使用正则匹配 script,匹配到之后,做删除,这个方法很麻烦,不推荐
2.利用第三方模块来处理:bs4模块
pip install bs4
BeautifulSoup它是用在爬虫里面,它能够筛选数据,清晰html数据
BeautifulSoup('', 'html.parser')
使用lxml的话需要安装 pip install lxml
BeautifulSoup('', 'lxml')
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(content, 'html.parser')
for tag in soup.find_all():
if tag.name == 'script':
tag.decompose()
desc = soup.text[:100]
article_obj = models.Article.objects.create(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 }}
<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>
KindEditor.ready(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 () {
editor.sync();
let title = $("#title").val();
let cate = $("#cate").val();
let tags = $("input[name='tags']:checkbox");
let tags_arr = []
$.each(tags, function (index, value) {
tags_arr.push($(this).val());
});
console.log(tags_arr);
var tags_str = tags_arr.join(',');
console.log(tags_str);
{#html = document.getElementById('editor_id').value;
{#html = K('#editor_id').val();
let content = $("#editor_id").val();
console.log(content);
$.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):
'''
文件返回格式:
//成功时
{
"error" : 0,
"url" : "http://www.example.com/path/to/file.ext"
}
//失败时
{
"error" : 1,
"message" : "错误信息"
}
:param request:
:return:
'''
if request.method == 'POST':
print(request.FILES)
file_obj = request.FILES.get('imgFile')
import os
from django.conf import settings
BASE_DIE = os.path.join(settings.BASE_DIR, 'media', 'article_img')
file_name = os.path.join(BASE_DIE, file_obj.name)
import uuid
new_str = str(uuid.uuid4())
new_uuid = new_str.replace('-', '')
new_file_name = new_uuid + '.' + file_obj.name.rsplit('.')[-1]
with open(new_file_name, 'wb') as f:
for line in file_obj:
f.write(line)
return JsonResponse(
{
"error": 0,
"url": "/media/article_img/%s" % new_file_name
}
)