Flask入門很輕松 (二)


轉載請在文章開頭附上原文鏈接地址:https://www.cnblogs.com/Sunzz/p/10959454.html

請求鈎子

在客戶端和服務器交互的過程中,有些准備工作或掃尾工作需要處理,比如:

  • 在請求開始時,建立數據庫連接;
  • 在請求開始時,根據需求進行權限校驗;
  • 在請求結束時,指定數據的交互格式;

為了讓每個視圖函數避免編寫重復功能的代碼,Flask提供了通用設置的功能,即請求鈎子。

請求鈎子是通過裝飾器的形式實現,Flask支持如下四種請求鈎子:

  • before_first_request
    • 在處理第一個請求前執行
  • before_request
    • 在每次請求前執行
    • 如果在某修飾的函數中返回了一個響應,視圖函數將不再被調用
  • after_request
    • 如果沒有拋出錯誤,在每次請求后執行
    • 接受一個參數:視圖函數作出的響應
    • 在此函數中可以對響應值在返回之前做最后一步修改處理
    • 需要將參數中的響應在此參數中進行返回
  • teardown_request:
    • 在每次請求后執行
    • 接受一個參數:錯誤信息,如果有相關錯誤拋出
    • 需要設置flask的配置DEBUG=False,teardown_request才會接受到異常對象。

代碼

config.py

class Config(object):
    DEBUG = True
    SECRET_KEY = "abcccddgadsag"
 

hook.py

from flask import Flask
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

@app.before_first_request
def before_firest_request():
    print("----- before_first_requets-----")
    print("系統初始化的時候,執行這個鈎子方法")
    print("會在接收到第一個用戶請求時,執行這里的代碼")


@app.before_request
def before_request():
    print("----before request")
    print("每一次接收到用戶請求時,執行這個鈎子方法")
    print("一般可以用來判斷權限,或者轉換路由參數或者預處理客戶端的請求的數據")


@app.after_request
def after_request(response):
    print("----after_request----")
    print("在處理請求以后,執行這個鈎子方法")
    print("一般可以用於記錄會員/管理員的操作歷史,瀏覽歷史,清理收尾的工作")
    response.headers["Content-Type"] = "application/json"
    return response


@app.teardown_request
def teardown_request(exc):
    print("----teardown_request----")
    print("在每一次請求以后,執行這個鈎子方法,如果有異常錯誤,則會傳遞錯誤異常對象到當前方法的參數中")
    print(exc)


@app.route("/hook")
def hook():
    print("----這是視圖函數----")
    print("視圖函數被運行了")
    return "這是視圖函數"


if __name__ == '__main__':
    app.run(host="127.0.0.1", port=80)

  • 請求時的打印:
----- before_first_requets-----
系統初始化的時候,執行這個鈎子方法
會在接收到第一個用戶請求時,執行這里的代碼
----before request
每一次接收到用戶請求時,執行這個鈎子方法
一般可以用來判斷權限,或者轉換路由參數或者預處理客戶端的請求的數據
----這是視圖函數----
視圖函數被運行了
----after_request----
在處理請求以后,執行這個鈎子方法
一般可以用於記錄會員/管理員的操作歷史,瀏覽歷史,清理收尾的工作
----teardown_request----
在每一次請求以后,執行這個鈎子方法,如果有異常錯誤,則會傳遞錯誤異常對象到當前方法的參數中
None

異常捕獲

主動拋出HTTP異常

  • abort 方法
    • 拋出一個給定狀態代碼的 HTTPException 或者 指定響應,例如想要用一個頁面未找到異常來終止請求,你可以調用 abort(404)。
  • 參數:
    • code – HTTP的錯誤狀態碼
# abort(404)
abort(500)

拋出狀態碼的話,只能拋出 HTTP 協議的錯誤狀態碼

捕獲錯誤

  • errorhandler 裝飾器
    • 注冊一個錯誤處理程序,當程序拋出指定錯誤狀態碼的時候,就會調用該裝飾器所裝飾的方法
  • 參數:
    • code_or_exception – HTTP的錯誤狀態碼或指定異常
  • 例如統一處理狀態碼為500的錯誤給用戶友好的提示:
@app.errorhandler(500)
def internal_server_error(e):
    return '服務器搬家了'
  • 捕獲指定異常類型
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
    return '除數不能為0'

上下文

上下文:即語境,語意,在程序中可以理解為在代碼執行到某一時刻時,根據之前代碼所做的操作以及下文即將要執行的邏輯,可以決定在當前時刻下可以使用到的變量,或者可以完成的事情。

Flask中有兩種上下文,請求上下文(request context)和應用上下文(application context)。

Flask中上下文對象:相當於一個容器,保存了 Flask 程序運行過程中的一些信息。

  1. application 指的就是當你調用app = Flask(__name__)創建的這個對象app
  2. request 指的是每次http請求發生時,WSGI server(比如gunicorn)調用Flask.__call__()之后,在Flask對象內部創建的Request對象;
  3. application 表示用於響應WSGI請求的應用本身,request 表示每次http請求;
  4. application的生命周期大於request,一個application存活期間,可能發生多次http請求,所以,也就會有多個request

請求上下文(request context)

思考:在視圖函數中,如何取到當前請求的相關數據?比如:請求地址,請求方式,cookie等等

在 flask 中,可以直接在視圖函數中使用 request 這個對象進行獲取相關數據,而 request 就是請求上下文的對象,保存了當前本次請求的相關數據,請求上下文對象有:request、session

  • request
    • 封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。
  • session
    • 用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息。

應用上下文(application context)

它的字面意思是 應用上下文,但它不是一直存在的,它只是request context 中的一個對 app 的代理(人),所謂local proxy。它的作用主要是幫助 request 獲取當前的應用,它是伴 request 而生,隨 request 而滅的。

應用上下文對象有:current_app,g

current_app

應用程序上下文,用於存儲應用程序中的變量,可以通過current_app.name打印當前app的名稱,也可以在current_app中存儲一些變量,例如:

  • 應用的啟動腳本是哪個文件,啟動時指定了哪些參數
  • 加載了哪些配置文件,導入了哪些配置
  • 連接了哪個數據庫
  • 有哪些可以調用的工具類、常量
  • 當前flask應用在哪個機器上,哪個IP上運行,內存多大
current_app.name
current_app.test_value='value'

g變量

g 作為 flask 程序全局的一個臨時變量,充當者中間媒介的作用,我們可以通過它傳遞一些數據,g 保存的是當前請求的全局變量,不同的請求會有不同的全局變量,通過不同的thread id區別

g.name='abc'

注意:不同的請求,會有不同的全局變量

兩者區別:

  • 請求上下文:保存了客戶端和服務器交互的數據
  • 應用上下文:flask 應用程序運行過程中,保存的一些配置信息,比如程序名、數據庫連接、應用信息等
from flask import Flask
# 新增一個配置文件,在配置文件中設置配置信息
from config import Config
from flask import request

app = Flask(__name__)
app.config.from_object(Config)



"""請求上下文"""
class Model(object):
    def __init__(self):
        print("模型接受到數據,num=%s" % request.args.get("username") )

@app.route("/context")
def context():
    Model()
    return "ok"

@app.route("/context2")
def context2():
    Model()
    return "ok"

"""應用上下文"""
from flask import current_app
@app.route('/context3')
def context3():

    # current_app 只是app對象在視圖被請求時的一個代理對象[別名對象]
    print( current_app.username ) # 我們可以直接調用app對象所擁有的屬性和方法
    return "應用上下文"

from flask import g
class Model2(object):
    def __init__(self):
        print("模型接受到數據,num=%s" % g.username )



@app.route('/context4')
def context4():
    # g是一個臨時的全局對象,只會在本次請求中獲取到數據
    g.username = request.args.get("username")
    Model2()
    return "應用上下文"

if __name__ == '__main__':
    # app 系統應用對象
    app.username='應用上下文的username'
    print('----運行項目之前----')
    app.run()

Flask-Script 擴展

安裝命令:

pip install flask-script

集成 Flask-Script到flask應用中

from flask import Flask

app = Flask(__name__)

"""使用flask_script啟動項目"""
from flask_script import Manager
manage = Manager(app)

@app.route('/')
def index():
    return 'hello world'

if __name__ == "__main__":
    manager.run()

Flask-Script 還可以為當前應用程序添加腳本命令

"""自定義flask_script終端命令"""
from flask_script import Command
class HelloCommand(Command):
    """命令的相關描述"""
    def run(self):
        with open("text.txt","w") as f:
            f.write("hello\r\nhello")
            pass

        print("這是執行了hello命令")

manage.add_command('hello', HelloCommand() )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM