flask-restful + flask-migrate + flask-csrf + 给类视图增加多个装饰器

一、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接口
  • 模板

    扫描二维码关注公众号,回复: 8972308 查看本文章
{% 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


通过实验,最终找到使用方法
{{csrf_token}}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论: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方法加登录装饰器
    在这里插入图片描述

发布了107 篇原创文章 · 获赞 43 · 访问量 6159

猜你喜欢

转载自blog.csdn.net/langdei/article/details/102598536
今日推荐