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

{% 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 · 訪問量 7074
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章