所谓的后台管理,也就是对各个表格的增删改查,显示起来也是不尽相同。
分页用之前写好的类,直接套上去就能用了。
整个写的虽然有些乱,不过还是十分不错的,逻辑很清晰,代码分布有些乱
注意:整个django没有写 xss 攻击防护,小心被攻击啊
1.主页
image.png主页上的菜单可筛选数据,通过 get 方式获得 URL 中的 article id,进行筛选文章。
image.png
2.登陆页面
登陆和注册都是由 form 来写的,点击验证码可以更换新的验证码,同时 session 中的验证码一齐更改
image.png
注册页面
image.png
其中包含了对验证码的验证,验证码存在 request.session 中,便于提取和修改,登陆和注册页面的 input 和校验都在 form 中完成,form 可以校验数据和保存上一次输入的值,
我们整个页面提交是由 form 表单来做的,一般来说,点击 submit 提交就会发送数据到 action 中指定的路径,效果就是刷新页面,丢失输入的数据,不过数据已经发送到了后台,
利用 django 的 form 组件就不会丢失上次输入的数据。
3.后台管理
1.png搜索条件中对于保留上次输入的值,是利用用户请求的 URL 中匹配出来的 kwargs 获取的,,
1.png
URL 设置为 /backend/article-2-2.html 的形式,对于每一列,只需要修改其中一个数据,而另一个在 kwargs 中获得,再在页面中检测是否选中。。
也是利用筛选来做的,而各种效果就是 hover , hide 的调用,好看的button 和图标是用 bootstrap 和 font-awesome 来做的
4.文章管理
点击文章的title就可以跳转到详细文章页面,在主页的title也可以跳转
image.png详细页面底下还有,评论和点赞,富文本编辑框(KindEditor),
评论和点赞是关于用户id在各个表中筛选出来的,(发表评论没有写)
image.png
富文本编辑框是直接引用插件的来完成的,点赞和踩就是发送一个ajax链接给后台,页面不需要刷新,用 js 修改一下就行了(这个我没做),评论有评论的表格,筛选获取就行,
做这个东西最重要的是表格之间的关系和筛选数据,
需要建立了很多张表格,彼此互相关联才行。
5.页面左边也是可以点击筛选的
image.png筛选的方式基本都差不多,不过在时间筛选上,要十分注意格式化时间字符串,用 strftime(这个是数据库内置的方法),
6.报障系统
(说成是系统我觉得有些过了,这个不过就是一个处理网页罢了)
这个也就是用户提交单子,给特定的人去取单,处理,其中的用户提交单子之后的状态转变是很关键的一点
image.png
效果可以设置的更好看一些,不过这个费事,我就没怎么调,直接在 bootstrap 和 font-awesome 上面找就行了
用户创建报障单,KindEditor插件
image.png
这个报障中十分重要的一点就是,普通用户提交trouble,管理员解决trouble之间的关系,和各个管理员之间对报障单的争夺,只有第一个点击的人才能获得单子
管理者取单
1.png
1.png
可以修改和不能修改之间的状态的改变,改变之间又联系在一起,这个部分写的不是很完善,填坑要做很多改善啊
图表
这个还是有必要记录一下的,用的插件是 hightchart,百度的echart也可以,用法都类似的,只需要传入图表所需要的数据类型就可以使得图表出现数据了
image.png
程序:
boke.zip
链接:https://pan.baidu.com/s/1aYGgv2S7PdflQoLMiIXe0w 密码:jpou
EdmureBlog.zip
链接:https://pan.baidu.com/s/1ThmBOgR4ofFLx4LDFYH_Ww 密码:ovpo
(整个写的有些乱,但是基本上还是不错的,基本该有都有,修改一下就可以用了,注意:登陆和注册有些小问题,)
note
一、瀑布流
- 布局
- 文档,窗口,滚动
- 面向对象的封装: this,that
二、报障系统
需求分析
- 报障
用户:
提交报账单
自己报障记录
处理着:
查看所有人报障单
处理报账单
- 知识库(博客)
主页:
展示最新文章
展示最热文章
展示评论最多文章
分类查看
个人博客:
个人博客主页
个人博客文章详细:赞,踩,评论
个人博客分类:标签、分类、时间
个人博客主题定制:后台修改
后台管理:
个人信息管理
个人标签
个人分类
个人文章
数据库设计:
用户表: uid,username,pwd,email,img,
博客表: bid,surfix,theme,title,summary, FK(用户表,unique)=OneToOne(用户表)
互粉表: id 明星ID(用户表) 粉丝ID(用户表)
2 1
1 2
1 3
5 3
报障单:UUID title detail user(用户表) processor(用户表 null) status(待处理,处理中,已处理) 创建时间 处理事件
分类表:caption Fk(博客bid)
标签表:caption Fk(博客bid)
文章:id,title,summary,ctime,FK(个人分类表),主站分类(choices)
文章详细:detail OneToOne(文章)
文章标签关系: 文章ID 标签ID
赞踩文章关系: 文章ID 用户ID 赞或踩(True,False) 联合唯一索引:(文章ID 用户ID )
评论表:id,content,FK(文章),FK(user),ctime,parent_comment_id
三、程序目录结构
project
- APP(repository) - 数据仓库(操作数据Model)
- APP(backend) - 后台管理
- APP(web) - 首页,个人博客
- utils - 工具包(公共模块)
工作安排:
1. 需求分析
2. 数据库设计思路
3. 实现数据库设计(Admin添加数据)
4. 主站:分类(主站)查看+分页
- 标题菜单:母版
- 登录成功: session['username'] = 'root'
- 主页html:
判断是否有用户:显示用户名
否则 : 登录,注册
<div class="pg-header">
{% if request.session.username %}
<a>{{ request.session.username }}</a>
{% else %}
<a>登录</a><a>注册</a>
{% endif %}
</div>
- 博文内容布局:
div div -> float => 图片下方空白
<a></a>asdflkjasdfkj => 文字环绕
- URL分类筛选:
url(r'^all/(?P<article_type_id>\d+).html$', home.index, name='index'),
url(r'^', home.index),
index根据kwargs判断是否分类查询?
a. 生成分类菜单
b. 考虑是否选中
c. 根据条件model.xxx.objects.filter(**kwargs)
- URL:
from django.urls import reverse
url(r'^all/(?<article_type_id>\d+).html$', home.index, name='index'),
在HTML中:{% url "index" article_type_id=1 %} => all/1.html
在views中:reverse('index',kwargs={"article_type_id":1}) =>all/1.html
url(r'^all/(\d+).html$', home.index, name='index'),
在HTML中:{% url "index" 1 %} =>all/1.html
在views中:reverse('index',args=(1,)) =>all/1.html
- 利用reverse+分页组件完成:分类查看+分页
5. 登录,注册
- 密码:数字,字母,特殊字符
- 密码两次输入一致
提交:
v = MyForm(request.GET) # 6个字段
if v.is_valid():
pass
密码示例:RegexField自定义密码验证规则
password = forms.RegexField(
'^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%\^\&\*\(\)])[0-9a-zA-Z!@#$\%\^\&\*\(\)]{8,32}$',
min_length=12,
max_length=32,
error_messages={'required': '密码不能为空.',
'invalid': '密码必须包含数字,字母、特殊字符',
'min_length': "密码长度不能小于8个字符",
'max_length': "密码长度不能大于32个字符"}
)
class RegisterForm(BaseForm, django_forms.Form):
username = django_fields.CharField()
password = django_fields.CharField()
confirm_pwd = django_fields.CharField()
def clean(self):
v1 = self.cleaned_data['password']
v2 = self.cleaned_data['confirm_pwd']
if v1 == v2:
pass
else:
from django.core.exceptions import ValidationError
raise ValidationError('密码输入不一致')
def register(request):
v = RegisterForm(request.POST)
if v.is_valid():
pass
else:
v.errors['username']
v.errors['__all__']
v.errors[NON_FIELD_ERRORS]
{
__all__: [],
username: [],
password: []
confirm_pwd: []
}
return render(request, 'register.html', {'v':v})
register.html
{{v.errors.username.0}}
{{v.non_field_errors}}
补充: 验证码
1.点击更换验证码
2.验证码到底是否有必要是图片?有
3.
服务端:
a. session中保存随机验证码,如:87fs
b. 在页面中显示图片
客户端:
a. 显示图片
b. 在cookie中保存sessionid
验证码图片
验证码字符串:87fs
sessionid='asdfasdfasdfasdfasdfasdf09'
{
"asdfasdfasdfasdfasdfasdf09": {'ck': 87fs}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
"ffsdfsdfsdfsdfsqq243234234": {'ck': 98fd}
}
ffsdfsdfsdfsdfsqq243234234 : 9999
使用:
check_code.py
Monaco.ttf
<img src="/shizhengwen.html" onclick="changeImg(this);">
<script>
function changeImg(ths) {
ths.src = ths.src + "?"; # 这个可以做到刷新验证码
}
</script>
def xiaoyun(request):
if request.method == "GET":
return render(request,'xiaoyun.html')
else:
input_code = request.POST.get('code')
check_cd = request.session['check_code']
print(input_code,check_cd)
return HttpResponse('...')
def shizhengwen(request):
"""生成验证码图片"""
# f = open('static/imgs/avatar/20130809170025.png','rb')
# data = f.read()
# f.close()
f = BytesIO()
img, code = create_validate_code()
request.session['check_code'] = code
img.save(f, 'PNG')
# request.session['CheckCode'] = code
return HttpResponse(f.getvalue())
补充: 一个月免登陆
request.session.set_expiry(60 * 60 * 24 * 30)
SESSION_COOKIE_AGE = 1209600
6. 个人博客
个人主页:http://127.0.0.1:8000/wupeiqi.html
/(\w+).html -> func(site) # wupeiqi
# 个人信息
# 博客信息
- 数据库字段+CSS文件名(warm,default)
文章最终:http://127.0.0.1:8000/wupeiqi/5.html
# 根据当前 wupeiqi + 5
obj = article.objects.filter(nid=5,blog=blog).first()
冗余
# 富文本编辑框
CKEditor
UEEditor
TinyEditor
KindEditor
# 下载插件
# 基本使用KindEditor
个人筛选:
http://127.0.0.1:8000/wupeiqi/tag/2.html
http://127.0.0.1:8000/wupeiqi/category/3.html
http://127.0.0.1:8000/wupeiqi/date/2017-02.html
# 公告
# 分类
# 标签
# 时间
# 过滤
url(r'^(?P<site>\w+)/(?P<condition>((tag)|(date)|(category)))/(?P<val>\w+-*\w*).html$', home.filter),
# 当前博客id、
# 数据库内置时间格式化函数
注意:个人主题定制
7. 后台管理
用户:
- 普通用户(知识库+提交报障单+个人信息)
- 管理员 (知识库+提交报障单+个人信息+处理报障单)
- 超级管理员
- (知识库+提交报障单+个人信息+处理报障单+报障统计信息)
- 权限管理
菜单:
- 知识库管理
文章
还债:KindEditor,XSS攻击
分类
标签
- 报障管理
个人保障
处理报障单
报障统计信息
画图
- 权限管理
菜单
权限
角色
========》后台管理页面《=======
依赖:
bootstrap
fontawsome
作业:
知识库管理:文章(Form验证)
8. 报障管理
后台管理:
普通用户:
报障列表,创建报障,修改,【查看解决方案】【评分】
工程师:
报障列表【自己 or 未】
列表:
models.tb.objects.filter(Q(processor_id=1)|Q(status=1)).order_by('status')
查看报障单id=1:
接单:v = models.tb.objects.filter(id=1,status=1).update(processor_id=22,status=2)
处理:
填写解决方案,提交status=3
===》 模板
老板:
查看所有信息
页面:
图
列表
# 每个处理者,
# 每个月处理了多少订单
id 创建时间 内容 处理者
1 2017-02-01 11:11 1
2 2017-03-01 11:11 11
3 2017-04-01 11:11 2
4 2017-05-01 11:11 1
5 2017-02-02 11:11 1
1. 思路
处理者列表 = select 处理着 from tb
for 处理者 in 处理者列表:
v = select * from tb where 处理者=处理者 group by 创建时间(2017-02)
2. 思路
# 每个月份全部门处理的订单个数
select * from tb group by 创建时间(%Y-%m)
select
创建时间(%Y-%m),
(select count(id) from tb as T2 where 处理者=1 and T2.ctime = T1.ctime ),
(select count(id) from tb as T2 where 处理者=2 and T2.ctime = T1.ctime ),
from tb as T1 group by 创建时间(%Y-%m)
年月 id=1 id=2
2017-02 2
2017-03 0
2017-04 0
2017-05 1
sql 注入
user = input('请输入用户名') # xx or 1=1 -- (-- 是注释)
pwd = input('请输入密码') # 123
sql = "select * from user where username=%s and password=%s" %(user,pwd,)
select * from user where username=xx or 1=1 -- and password=123
and 开始的都被注释掉了
所以这句是永远成立的
cursor.execute(sql)
cursor.fetchall()
要注意一点,就是在pycharm中对时间字段修改时只能以一段1528819200000 这种类型的时间戳形成存储,想要修改成 2017-03-17 05:49:18.777722 格式的需要在 admin 或自己写个页面来存储到数据库。。
网友评论