我的第一个python web开发框架(15)——公司介绍编辑功能
完成登录以后,就会进入后台管理系统的主界面,因为这个是小项目,所以导航菜单全部固化在HTML中,不能修改。一般后台还会有一个欢迎页或关键数据展示的主页面,小项目也没有多大的必要,所以登录后直接进入公司介绍编辑页面。
首先我们来看一下公司介绍页面内容
看上去功能好像很简单,其实我们要处理的东西还是挺多的。
从页面上看,我们需要有一个记录读取的接口,来获取公司介绍的内容,并展示在页面上。当然现在数据库里面没有记录存在,所以我们还需要向数据库的信息表(infomation)中插入一条公司介绍的记录,这样好直接进行编辑(因为公司介绍不会有很多条记录,一般定了后就不会再改变,所以只需要在数据库的信息表里插入一条就可以了)
另外,从界面上看,我们还需要有一个上传文件的接口,可以上传图片和文件;还需要一个更新公司介绍内容的接口。
还有需要修改几个地方,有上传文件,肯定需要有下载的接口,所以需要增加一个下载的路由(python与其他语言不一样的地方是,所有访问都必须通过路由,所以上传的或放在目录中的文件需要统一定义一个接口来处理,不然用户访问不了,虽然有点麻烦,但这样处理也安全很多,用户上传任何含有木马或程序的文件,它也无法在服务器端执行);nginx配置文件也需要修改一下,增加下载路径规则,这样就可以直接通过nginx访问下载路径了。
向数据库中添加公司介绍记录
运行pgAdmin连上数据库,然后按第4章的做法,打开sql查询分析器,运行下面代码添加一条数据库记录
INSERT INTO infomation(id, title) VALUES (1, '公司介绍');
添加公司介绍记录读取接口
@get('/api/about/')
def callback():
"""
获取指定记录
"""
sql = """select * from infomation where id = 1"""
# 读取记录
result = db_helper.read(sql)
if result:
# 直接输出json
return web_helper.return_msg(0, '成功', result[0])
else:
return web_helper.return_msg(-1, "查询失败")
因为公司介绍id添加后不会再改变,所以sql语句直接绑死id为1,另外,执行数据库查询以后,返回的是列表,所以返回记录时要加上序号:result[0]
启动debug(对main.py点击右键=》debug),将用户登录判断那两行注释掉(不然直接访问会返回-404,“您的登录已失效,请重新登录”提示),在浏览器输入:http://127.0.0.1:9090/api/about/就可以看到返回结果(结果的中文字符是unicode编码,需要用站长工具转换一下才可以转为下载效果)
{"msg": "成功", "data": {"content": "", "front_cover_img": "", "id": 1, "title": "公司介绍", "add_time": "2017-10-31 14:17:45"}, "state": 0}
添加公司介绍内容修改接口
@put('/api/about/')
def callback():
"""
修改记录
"""
front_cover_img = web_helper.get_form('front_cover_img', '图片')
content = web_helper.get_form('content', '内容', is_check_special_char=False)
# 防sql注入攻击处理
content = string_helper.filter_str(content, "'")
# 防xss攻击处理
content = string_helper.clear_xss(content) # 更新记录
sql = """update infomation set front_cover_img=%s, content=%s where id=1"""
vars = (front_cover_img, content,)
# 写入数据库
db_helper.write(sql, vars) # 直接输出json
return web_helper.return_msg(0, '成功')
因为公司介绍只需要一条记录就够了,前面使用手动方式向数据库添加记录,所以代码中我们就不需要写添加的方法
修改记录使用put方式接收:@put('/api/about/')
从界面图片中可以看到,有文章标题、首页图片和文章内容,因为标题不需要进行修改,所以我们修改接口只需要处理剩下两项就可以了。
因为提交的内容含有HTML代码,所以使用web_helper.get_form提取值时,需要使用is_check_special_char参数,设置为不检查特殊符号,不然会接收不了。另外接收到参数值以后,我们需要对它进行防sql注入和防xss处理。
clear_xss()函数是string_helper包新增的清除xss攻击标签用的,它会过滤掉xss的攻击代码。详细代码如下:
def clear_xss(html):
"""
清除xss攻击标签
:param html: 要处理的html
:return:
"""
tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'strong', 'ul']
tags.extend(
['div', 'p', 'hr', 'br', 'pre', 'code', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'del', 'dl', 'img', 'sub', 'sup', 'u',
'table', 'thead', 'tr', 'th', 'td', 'tbody', 'dd', 'caption', 'blockquote', 'section'])
attributes = {'*': ['class', 'id'], 'a': ['href', 'title', 'target'], 'img': ['src', 'style', 'width', 'height']}
return bleach.linkify(bleach.clean(html, tags=tags, attributes=attributes))
clear_xss()函数中我们使用了bleach这个库(需要安装:pip install bleach),它是一个基于白名单、通过转义或去除标签和属性的方式,来对HTML文本净化的python库。
我们在string_helper_test.py这个测试单元中添加一个测试用例,来测试一下这个函数的使用效果
def test_clear_xss(self):
print('-----test_clear_xss------')
print(string_helper.clear_xss('<script src="javascript:alert(1);">abc</script>'))
print(string_helper.clear_xss('<iframe src="javascript:alert(1);">abc</iframe>'))
print(string_helper.clear_xss('<div style="width:0;height:0;background:url(javascript:document.body.onload = function(){alert(/XSS/);};">div</div>'))
print(string_helper.clear_xss('<img src = "#"/**/onerror = alert(/XSS/)>'))
print(string_helper.clear_xss('<img src = j ava script:al er t(/XSS/)>'))
print(string_helper.clear_xss("""<img src = j
ava script :a ler t(/xss/)>"""))
print(string_helper.clear_xss('<img src="javacript:alert(\'abc\')"></img>'))
print(string_helper.clear_xss('<img src="https://www.baidu.com/img/baidu_jgylogo3.gif"></img>'))
print(string_helper.clear_xss('<p src="javascript:alert(1);">abc</p>'))
print(string_helper.clear_xss("""<input type="text" value="琅琊榜" onclick="javascript:alert('handsome boy')">"""))
print(string_helper.clear_xss('<p onclick="javascript:alert("handsome boy")>abc</p>'))
print(string_helper.clear_xss('<a href="javascript:alert(1);">abc</a>'))
print(string_helper.clear_xss('<a href="/api/">abc</a>'))
print(string_helper.clear_xss('<a href="http://www.baidu.com">abc</a>'))
print(string_helper.clear_xss('<marquee onstart="alert(/XSS/)">文字</marquee>'))
print(string_helper.clear_xss('<div style="" onmouseenter="alert(/XSS/)">文字</div>'))
print(string_helper.clear_xss('<li style = "TEST:e-xpression(alert(/XSS/))"></li>'))
print(string_helper.clear_xss('<input id = 1 type = "text" value="" <script>alert(/XSS/)</script>"/>'))
print(string_helper.clear_xss('<base href="http://www.labsecurity.org"/>'))
print(string_helper.clear_xss('<div id="x">alert%28document.cookie%29%3B</div>'))
print(string_helper.clear_xss('<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>'))
执行后输出结果:
------ini------
-----test_clear_xss------
<script src="javascript:alert(1);">abc</script>
<iframe src="javascript:alert(1);">abc</iframe>
<div>div</div>
<img src="#">
<img src="j">
<img src="j">
<img>
<img src="https://www.baidu.com/img/baidu_jgylogo3.gif">
<p>abc</p>
<input onclick="javascript:alert('handsome boy')" type="text" value="琅琊榜">
<p>abc</p>
<a>abc</a>
<a href="/api/" rel="nofollow">abc</a>
<a href="http://www.baidu.com" rel="nofollow">abc</a>
<marquee onstart="alert(/XSS/)">文字</marquee>
<div>文字</div>
<li></li>
<input <script="" id="" type="text" value="">alert(/XSS/)"/>
<base href="<a href="http://www.labsecurity.org" rel="nofollow">http://www.labsecurity.org</a>">
<div id="x">alert%28document.cookie%29%3B</div>
<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>
------clear------
可以看到,对于富文本编辑器提交的代码,bleach基本满足了我们的防范xss攻击的处理需求
添加上传接口(PS:我们使用的文本编辑器是百度的ueditor,因为它没有python的上传处理代码,所以我们需要动手编辑上传接口,以及html上也要进行对应的修改)
#!/usr/bin/evn python
# coding=utf-8 import os
from bottle import post, request
from common import datetime_helper, random_helper, log_helper @post('/api/files/')
def callback():
"""
修改记录
"""
# 初始化输出值
result = {
"state": "FAIL",
"url": "",
"title": "上传失败",
"original": ""
}
# 获取上传文件
try:
# upfile为前端HTML上传控件名称
upload = request.files.get('upfile')
# 如果没有读取到上传文件或上传文件的方式不正确,则返回上传失败状态
if not upload:
return result # 取出文件的名字和后缀
name, ext = os.path.splitext(upload.filename)
# 给上传的文件重命名,默认上传的是图片
if ext and ext != '':
file_name = datetime_helper.to_number() + random_helper.get_string(5) + ext
else:
file_name = datetime_helper.to_number() + random_helper.get_string(5) + '.jpg'
upload.filename = file_name # 设置文件存储的相对路径
filepath = '/upload/' + datetime_helper.to_number('%Y%m%d') + '/'
# 组合成服务器端存储绝对路径
upload_path = os.getcwd() + filepath
# 如果目录不存在,则创建目录
if not os.path.exists(upload_path):
os.mkdir(upload_path)
# 保存文件
upload.save(upload_path + upload.filename, overwrite=True) # 设置输出参数(返回相对路径给客户端)
result['title'] = result['original'] = upload.filename
result['url'] = filepath + upload.filename
result['state'] = 'SUCCESS'
except Exception as e:
log_helper.error('上传失败:' + str(e.args)) # 直接输出json
return result
PS:这里只做了上传文件处理,没有上传成功以后存储到数据库中统一管理,如果前端反复上传,会造成服务器存储很多多余文件的问题,大家可以自己发挥想象与动手能力,看看怎么解决这个问题。对于这个问题会在第二部分统一处理。
添加上传文件存储文件夹:直接在项目的要目录下创建upload文件夹
修改main.py文件配置,并创建文件下载路由
导入的bottle库添加response, static_file这两个包,response用于设置输出文件类型为二进制数据传输格式,这样设置后,上传的各种类型文件都可以下载;static_file是使用安全的方式读取文件并输出到客户端
from bottle import default_app, get, run, request, hook, route, response, static_file
在第26行插入下面代码,初始化上传文件存储路径
# 定义upload为上传文件存储路径
upload_path = os.path.join(program_path, 'upload')
添加下载文件访问路由,设置后只要放在upload目录下的文件都可以直接通过浏览器下载
@get('/upload/<filepath:path>')
def upload_static(filepath):
"""设置静态内容路由"""
response.add_header('Content-Type', 'application/octet-stream')
return static_file(filepath, root=upload_path)
做完以上设置,上传与更新就没有问题了,上传的图片直接使用http://127.0.0.1:9090/upload/xxx.jpg方式就可以访问了,如果想要使用81端口,也就是通过nginx访问,那就需要再配置一下
打开nginx配置文件 :E:\Service\nginx-1.11.5\conf\nginx.conf
将location ~* ^/(index|api)/ 修改为 location ~* ^/(index|api|upload)/
然后在windows任务管理器(键盘同时按Ctrl+Alt+Del键,点击启动任务管理器),找到nginx_service.exe,右键=》结束进程树
重新打开服务(控制面板=》所有控制面板项=》管理工具=》服务),启动nginx_service服务
前端页面相关修改
向/lib/ueditor/1.4.3/目录中添加python文件夹,将添加config.json这个配置项
修改/lib/ueditor/1.4.3/ueditor.config.js 配置项中 服务器统一请求接口路径 为 /api/files/
本文对应的源码包里有ueditor编辑器最新代码(刚刚去百度下载的),去掉了多余的文件,大家可直接删除lib目录里的ueditor这个文件夹,使用源码包里的替换上去就可以了
前端页面的javascript脚本添加了ueditor编辑器初始化、文件上传和表单提交等功能,可直接替换about_edit.html文件,具体大家自己研究一下。
最终效果:
另外,联系我们的功能与公司介绍差不多,在这里留一下作业给大家自己尝试做一个联系我们编辑页面出来,下一篇会给联系我们编辑页面源码给大家
版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
python开发QQ群:669058475(本群已满)、733466321(可以加2群) 作者博客:http://www.cnblogs.com/EmptyFS/
我的第一个python web开发框架(15)——公司介绍编辑功能的更多相关文章
- 我的第一个python web开发框架(41)——总结
我的第一个python web开发框架系列博文从17年6.7月份开始写(存了近十章稿留到9月份才开始发布),到今天结束,一年多时间,想想真不容易啊. 整个过程断断续续,中间有段时间由于工作繁忙停了好长 ...
- 我的第一个python web开发框架(14)——后台管理系统登录功能
接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...
- 我的第一个python web开发框架(3)——怎么开始?
小白与小美公司经过几次接触商谈,好不容易将外包签订了下来,准备开始大干一场.不过小白由于没有太多的项目经验,学过python懂得python的基本语法,在公司跟着大家做过简单功能,另外还会一些HTML ...
- 我的第一个python web开发框架(1)——前言
由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...
- 我的第一个python web开发框架(2)——一个简单的小外包
第一部分说明 第一部分大概有20来章,主要讲的是一些开发常识.开发前中后期准备内容.开发环境与服务器部署环境安装设置.python基础框架结构与功能等内容,代码会比较简单. 本系列会以故事的方式,向大 ...
- 我的第一个python web开发框架(22)——一个安全小事故
在周末的一个早上,小白还在做着美梦,就收到了小美的连环追魂call,电话一直响个不停. 小白打着哈欠拿起电话:早上好美女. 小美:出事了出事了,我们公司网站一早访问是一片空白,什么内容都没有了,你赶急 ...
- 我的第一个python web开发框架(4)——数据库结构设计与创建
小白做好前端html设计后,马上开始进入数据库结构设计步骤. 在开始之前,小白回忆了一下老大在公司里培训时讲过的数据库设计解说: 对于初学者来说,很多拿到原型时不知道怎么设计数据表结构,这是很正常的事 ...
- 我的第一个python web开发框架(18)——前台页面与接口整合
由于我们前后台系统没有分开,所以前台页面调用接口时,可以直接使用后台管理系统已经完成的接口,不过后台管理系统接口的访问加上了登录验证,所以需要将前台要用到的接口进行处理,让它们设置到白名单当中 我们打 ...
- 我的第一个python web 开发框架
1:数据库结构设计与创建 小白做好前端html设计后,马上开始进入数据库结构设计步骤. 在开始之前,小白回忆了一下老大在公司里培训时讲过的数据库设计解说: 对于初学者来说,很多拿到原型时不知道怎么设计 ...
随机推荐
- 修改yum源
安装 centos 之后,修改 yum 源到其它国内源 1. 备份原文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Ba ...
- 基于MyBatis3.0.6的基本操作介绍
每 一 个 MyBatis 的 应 用 程 序 都 以 一 个 SqlSessionFactory 对 象 的 实 例 为 核 心 .SqlSessionFactory本身是由SqlSessionFa ...
- ASP.NET Core 2.0 支付宝当面付之扫码支付
前言 自从微软更换了CEO以后,微软的战略方向有了相当大的变化,不再是那么封闭,开源了许多东西,拥抱开源社区,.NET实现跨平台,收购xamarin并免费提供给开发者等等.我本人是很喜欢.net的,并 ...
- HDU2089 暴力打表
62的判断就是倒过来没有26 hdu2089 #include<cstdio> #include<cstdlib> #include<iostream> #incl ...
- Java基础入门知识
Java编程入门知识 知识概要: (1)Java入门基本常识 (2)Java的特性跨平台性 (3)Java的编程环境的搭建 (4)Java的运行机制 (5)第一个Java小程序入门 (1)Java ...
- C#微信公众号/订阅号开发 接口源码
using System; using System.Web; using System.IO; using System.Text; using System.Web.Security; using ...
- springboot自定义配置源
概述 我们知道,在Spring boot中可以通过xml或者@ImportResource 来引入自己的配置文件,但是这里有个限制,必须是本地,而且格式只能是 properties(或者 yaml). ...
- ABAP 选择屏幕创建标签页
*&---------------------------------------------------------------------* *& Report ZTEST_TAB ...
- TensorFlow问题:The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
1. 问题描述 The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available o ...
- 笨鸟先飞之ASP.NET MVC系列之过滤器(05结果过滤器)
概念介绍 结果过滤器看名字就知道这个过滤器是针对方法所产生结果的,结果过滤器,主要在我们的动作方法结果返回前后执行. 如果我们需要创建结果过滤器需要实现IResultFilter接口. namespa ...