一、flask-restful
在django中
django restful(是一种api接口的设计规范,通常路由的编写不会出现动词)
get 请求 getuserinfo 获取到所有用户的所有信息
getuserinfo id 获取指定id用户的所有信息
getuserinfo name 获取执行用户名字的信息
getuserinfo age 获取指定年龄的用户信息
getuserinfo age name 获取年龄为xxx 名字为 xxx 的用户的信息
userinfo
增加用户的操作: def adduserinfo add_userinfo
获取用户信息: def get_userinfo get_userinfo
restful中 class userinfo:
def get:
获取数据
def post:
添加数据
def put:
修改数据
def delete:
删除数据
1. flask 中restful安装及配置,基本结构(路由的两种写法)
① 第一步:安装
安装插件:flask-restful
pip install flask-restful
相关安装包
② restful使用(配置,收集路由)
- main.py restful 配置信息
③ 基本结构(路由的两种写法)
from main import api
from flask_restful import Resource
## main.py中
api = Api(app) ## 负责收集路由 收集类视图的注册信息
- from flask_restful import Resource 中Resource的介绍
- from main import api 实例化api对象调用方法的介绍
- restful基本结构
2. 视图中使用restful
① get请求
- get请求初步封装
#-------------------------------restful-----------------------------
from main import api
from flask_restful import Resource
## 路由的写法(收集路由,收集类视图)Api 标明接口 v1版本 leave对leave的操作
@api.resource("/Api/v1/leave/")
class LeaveApi(Resource):
def get(self):
"""
处理get请求
获取资源
:return:
"""
result_data = {}
data = request.args
id = data.get("id")
# request_name = data.get("request_name")
if id:
leave = Leave.query.get(int(id))
if leave is not None:
result_data = {
"request_id":leave.request_id,
"request_name":leave.request_name,
"request_type":leave.request_type,
"request_end":str(leave.request_end),
"request_description":leave.request_description,
"request_start":str(leave.request_start),
"request_phone":leave.request_phone,
"request_status":leave.request_status,
}
else:
leaves = Leave.query.all() ## 使用数据
result_data = []
for leave in leaves:
info = {
"request_id": leave.request_id,
"request_name": leave.request_name,
"request_type": leave.request_type,
"request_end": str(leave.request_end),
"request_description": leave.request_description,
"request_start": str(leave.request_start),
"request_phone": leave.request_phone,
"request_status": leave.request_status,
}
result_data.append(info)
return result_data
- 效果演示
- 不传参获取所有数据
- 传入指定id查询指定数据
- 传入指定字段属性值进行查询
② post请求
- post请求函数
def post(self):
"""
处理post请求
:return:
"""
data = request.form
return "post请求%s" %data
- 效果演示
③ put请求
- put请求函数
def put(self):
"""
处理put请求
:return:
"""
data = request.form
return "put请求%s" % data
- 结果演示
④ delete请求
- delete请求函数
def delete(self):
"""
处理delete请求
:return:
"""
data = request.form
return "delete请求%s" % data
⑤ Django和flask中一些方法不同的获取方式
在Django中 put和delete传递的参数放在下面的文本中,
用request.body获取值
在flask中 put和 delete 传递的参数和post一样放在下面的文本框中,
用request.form.get获取值
3. 代码优化
① 规定返回格式,将其写在init初始化文件中
- 提取封装公共的返回结构
- 返回selt.result
② 封装get中冗余的代码
- get请求中代码冗余,将公共的地方封装
- 将数据结果封装成函数,方便调用
③ 封装get请求
- get请求封装 实现查询功能
from main import api
from flask_restful import Resource
## 路由的写法(收集路由,收集类视图)Api 标明接口 v1版本 leave对leave的操作
@api.resource("/Api/v1/leave/")
class LeaveApi(Resource):
def __init__(self):
super(LeaveApi, self).__init__()
self.result = {
"method": "get",
"version": "v1",
"data": ""
}
def create_data(self,leave):
"""
定义返回的数据
:return:
"""
result_data = {
"request_id": leave.request_id,
"request_name": leave.request_name,
"request_type": leave.request_type,
"request_end": str(leave.request_end),
"request_description": leave.request_description,
"request_start": str(leave.request_start),
"request_phone": leave.request_phone,
"request_status": leave.request_status,
}
return result_data
def get(self):
"""
处理get请求
获取资源
:return:
"""
result_data = {}
data = request.args
id = data.get("id")
# request_name = data.get("request_name")
if id:
leave = Leave.query.get(int(id))
if leave is not None:
result_data = self.create_data(leave)
else:
leaves = Leave.query.all() ## 使用数据
result_data = []
for leave in leaves:
info = self.create_data(leave)
result_data.append(info)
self.result["data"] = result_data
# result = {
# "method":"get",
# "version":"v1",
# "data":result_data
# }
return jsonify(self.result)
- 结果演示:
④ post请求封装
- post请求实现增加功能
def post(self):
"""
处理post请求 增加数据的功能
:return:
"""
data = request.form
leave = Leave()
leave.request_id = data.get("request_id")
leave.request_name = data.get("request_name")
leave.request_type = data.get("request_type")
# end = str(data.get("request_end"))
end = data.get("request_end")
request_end = datetime.date(*map(int,end.split('-')))
# leave.request_end = data.get("request_end")
leave.request_end = request_end
leave.request_description = data.get("request_description")
# start = str(data.get("request_start"))
start = data.get("request_start")
# request_start = datetime.date(*map(int,start.split('-')))
# leave.request_start = data.get("request_start")
leave.request_start = datetime.date(*map(int,start.split('-')))
leave.request_phone = data.get("request_phone")
leave.request_status = data.get("request_status")
leave.save()
self.result["method"] = "post"
self.result["data"] = self.create_data(leave)
return jsonify(self.result)
⑤ 封装put请求
- put请求实现更新功能
def put(self):
"""
处理put请求 更新数据
可以支持更改部分数据
根据id查询对象 ----》 id
修改的是 对象里面的属性
对象属性 ----》 setattr
:return:
"""
data = request.form
id = data.get("id") ## 假条id
leave = Leave.query.get(id) ## 找到被修改的数据 leave是一个对象
for key,value in data.items():
if key!= "id":
if hasattr(leave,key):
if key == "request_start" or key == "request_end":
value = datetime.date(*map(int,value.split('-')))
setattr(leave, key, value)
setattr(leave,key,value)
leave.merge()
self.result["method"] = "put"
self.result["data"] = self.create_data(leave)
return jsonify(self.result)
⑥ 封装delete请求
- delete请求实现删除功能
def delete(self):
"""
处理delete请求
:return:
"""
data = request.form
id = data.get("id")
leave = Leave.query.get(id)
leave.delete()
self.result["method"] = "delete"
self.result["data"] = self.create_data(leave)
return jsonify(self.result)
- 效果演示
4. 接口提供数据实现前后端分离
① 接口(api)介绍
- api接口提供数据的支持,将前端html和后端进行分离
- 返回的数据通常是json
- restful 风格的接口,命名不出现动词
- 接口开发的目的,增加数据的可用性,
- 前端(pc,app, 小程序,爬虫,)
写web页面,请求api接口获取数据,前端web现在ajax,vue
② 前后端分离demo
-
视图: (有两个函数)
- 提供返回页面的功能
- 提供返回数据的api接口
-
模板
{% extends "base.html" %}
{% block title %}
api demo
{% endblock %}
{% block label %}
api demo
{% endblock %}
{% block content %}
{% endblock%}
{% block script %}
<script src="/static/vendor/jquery/jquery.min.js"></script>
<script>
$.ajax({
url:"/Api/v1/leave/",
type:"get",
data:"",
success:function (data) {
console.log(data)
// 返回的数据可以通过列表在此页面展示给用户
},
error:function (error) {
console.log(error)
}
})
</script>
{% endblock %}
- 通过列表套字典的方式将数据传递给前端html模板
可以参照Django的前后端数据分离
二、Flask-migrate
1. flask-migrate的介绍
migrate是flask对数据模型的管理插件
在实际的开发环境中,经常会发生数据库修改的行为。一般我们修改数据库不会直接手动的去修改,而是去修改ORM对应的模型,然后再把模型映射到数据库中。这时候如果有一个工具能专门做这种事情,就显得非常有用了,而flask-migrate就是做这个事情的。flask-migrate是基于Alembic进行的一个封装,并集成到Flask中,而所有的迁移操作其实都是Alembic做的,他能跟踪模型的变化,并将变化映射到数据库中。
可通过Flask命令行界面或Flask-Script扩展名使用数据库操作。
官方文档:Flask-migrate
2. 使用flask-migrate原因
不同步更新问题
因为采用db.create_all在后期修改字段的时候,不会自动更改到数据库中,必须删除表,然后重新运行db.create_all才会重新映射,这样是不符合实际情况的。
因此flask-migrate就解决了这个问题,可以直接将修改的东西映射到数据库中。
3. 安装及使用介绍
pip install flask-migrate
migrate 插件通常不单独使用,需要结合flask的script插件进行使用。
能够解决 create_all 不足的问题:
解决migrate不同步更新表结构
4. 使用前的配置
-
配置main.py
-
使用migrate绑定app和db
migrate = Migrate(app,db)
-
配置manage.py
-
让python支持命令行工作
manager= Manager(app)
-
添加迁移脚本的命令到manager中
manager.add_command("db",MigrateCommand)
-
最后的代码
5. flask-migrate相关命令
- 初始化一个迁移脚本的环境,只需要执行一次
python manage.py db init
- 将模型生成迁移文件,只要模型更改了,就需要执行一次这个命令
python manage.py db migrate
- 将迁移文件真正的映射到数据库中。每次也需要执行一次这个命令
python manage.py db upgrade
- 回退操作
python manage.py downgrade
- 查看版本记录
python manage.py db history
6. 执行数据迁移操作步骤
- 迁移前初始化,生成迁移文件目录
python manage.py db init
- 生成迁移文件版本记录version
python manage.py db migrate
- 生成新版本,版本升级
python manage.py db upgrade
- 查看版本记录
python manage.py db history
三、flask中的CSRF
flask_wtf 的form表单类,csrf_token会随着form表单生成,但是不校验
flask-wtf自动生成csrf隐藏域
1. CSRF校验
使用:
- 开启csrf校验
- main.py中导入CSRFProtect csrf保护
- 效果:
2. 前端页面使用csrf
通过实验,最终找到使用方法
结论:form表单加隐藏域即可通过验证
3. 在测试的时候遇到CSRF解决办法
在测试的时候
- post、put、delete等可以加一个csrf_token键,
- 然后找个网页找个csrf_token值
- 将值复制进去
- 验证结果
4. 避免CSRF
- 实例化csrf保护
- 给要避免csrf的函数加装饰器
四、给类视图增加多个装饰器
1.method_decorators介绍
method_decorators 类属性,Resource会检测method_decorators类属性当中有没有给下面的方法增加装饰器
method_decorators 会给方法增加装饰器
method_decorators = [] 代表将该类中的所有方法都增加装饰器
2. 给类视图加多个装饰器
- 代码
### 类视图装饰器
def func1(func):
def inner():
print("func1装饰器")
func()
return inner
def func2(func):
def inner():
print("func2装饰器")
func()
return inner
class Demo(Resource):
method_decorators = [func1,func2]
def get(self):
"""
:return:
"""
return "get请求"
def post(self):
"""
:return:
"""
return "post 请求"
api.add_resource(Demo,"/Demo/") ##
## 装饰器相当于
@func2
@func1
def get():
pass
- get请求结果
- post请求结果
顺序,列表中先去遍历,func1先装饰,再在外面装饰func2
3. 给指定的方法装饰指定的装饰器
- get请求
- post请求
4. 给一个方法加多个装饰器
- 在restful中只给get方法加登录装饰器