Flask 快速入門

一、Flask 簡(jiǎn)介

Flask是一個(gè)使用 Python 編寫的輕量級(jí) Web 應(yīng)用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎則使用 Jinja2 。Flask使用 BSD 授權(quán)。

Flask也被稱為 “microframework” ,因?yàn)樗褂煤?jiǎn)單的核心,并且被設(shè)計(jì)為可擴(kuò)展形式。故而沒(méi)有提供一些重要的功能,例如數(shù)據(jù)庫(kù)和用戶認(rèn)證,所以開(kāi)發(fā)者可以自由選擇最適合程序的包,或者按照需求自行開(kāi)發(fā)。

社區(qū)成員開(kāi)發(fā)了大量的不同用途的擴(kuò)展,如果這還不能滿足需求,你還可以使用所有Python標(biāo)準(zhǔn)包或代碼庫(kù)。

image.png

二、Flask 安裝

一般安裝python后會(huì)自帶pip工具,方便下載安裝python各類庫(kù),如果沒(méi)有自行百度。

pip install flask

三、最簡(jiǎn)單Flask應(yīng)用

# app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run() # 啟動(dòng)服務(wù)器

寫完后直接用python運(yùn)行,默認(rèn)監(jiān)聽(tīng)本地5000端口,訪問(wèn)http://127.0.0.1:5000/就能看到Hello World!

四、初始化應(yīng)用

所有Flask程序都必須創(chuàng)建一個(gè)程序?qū)嵗?/code>,所有功能都是圍繞這個(gè)實(shí)例進(jìn)行的,接收自客戶端的所有請(qǐng)求都將轉(zhuǎn)交到這個(gè)對(duì)象處理。程序?qū)嵗荈lask類的對(duì)象,經(jīng)常使用下述代碼創(chuàng)建一個(gè)實(shí)例:

from flask import Flask
app = Flask(__name__)

五、路由和視圖函數(shù)

  • 路由

客戶端(如Web瀏覽器)把請(qǐng)求發(fā)送給Web服務(wù)器,Web服務(wù)器再把請(qǐng)求發(fā)送給Flask程序?qū)嵗绦驅(qū)嵗枰缹?duì)每個(gè)URL請(qǐng)求運(yùn)行哪些代碼,所以保存了一個(gè)URL到Python函數(shù)的映射關(guān)系。處理URL和函數(shù)之間關(guān)系的程序稱為路由。

  • 視圖函數(shù)

前面最簡(jiǎn)單的Flask應(yīng)用中定義了一個(gè)函數(shù)hello_world(),該函數(shù)被注冊(cè)為程序根地址(/)的處理程序,也就是訪問(wèn)http://127.0.0.1:5000/時(shí),會(huì)觸發(fā)服務(wù)器執(zhí)行hello_world()函數(shù),函數(shù)的返回值成為響應(yīng),是客戶端接收到的內(nèi)容,如果客戶端是Web瀏覽器,響應(yīng)就是返回給用戶的HTML文檔。
hello_world()這樣的用于處理請(qǐng)求的函數(shù)稱為視圖函數(shù)。視圖函數(shù)可以返回簡(jiǎn)單的HTML字符串,也可以返回一個(gè)完整的HTML文檔(這里就要用到Jinja2模板引擎啦)。

  • 注冊(cè)一個(gè)視圖函數(shù)最常用的方法就是用app.route():
@app.route("/")
def hello_world():
    pass
  • 限制路由的請(qǐng)求方法
@app.route("/", methods=["GET"])
def hello_world():
    pass

這樣,要是客戶端以POST的方式請(qǐng)求該路由,就會(huì)返回“405 Method Not Allowed”

  • 向路由函數(shù)傳參
    有的時(shí)候我們需要通過(guò)url獲取有用的信息,比如說(shuō)知道來(lái)訪者的姓名,以便在返回的歡迎語(yǔ)中加入他的名字。
@app.route("/hello/<string:name>")
def hello(name):
   return "hello, " + name

上例中,在定義該路由的訪問(wèn)路徑里加了一個(gè)<string:name>,并增加了一個(gè)同名函數(shù)參數(shù)。
更一般的情況是<type:param>,其中type是類型,常用的有string、int,param就是參數(shù)名,它會(huì)傳遞到路由函數(shù)的同名參數(shù)里。

六、啟動(dòng)服務(wù)器

當(dāng)Flask應(yīng)用被初始化且視圖函數(shù)定義好之后,就可以啟動(dòng)Flask應(yīng)用啦。

if __name__ == "__main__":
    app.run() # 默認(rèn)監(jiān)聽(tīng)本地5000端口
    # app.run(port=8080) 監(jiān)聽(tīng)8080端口

七、請(qǐng)求 - 響應(yīng)循環(huán)

說(shuō)到請(qǐng)求,必須要先介紹一下上下文

  • 上下文(Context)

上下文,在閱讀文章時(shí)經(jīng)常提到,意思是語(yǔ)境、語(yǔ)意。在程序設(shè)計(jì)中,上下文的概念也是類似的,你可以這么理解:
通俗地講,每一段代碼都有許多外部變量,比如一個(gè)函數(shù)需要傳入若干個(gè)必填的參數(shù)才能夠運(yùn)行,那些參數(shù)就是上下文的一部分,意味著該函數(shù)無(wú)法獨(dú)立運(yùn)行,需要上下文的支持。而許多函數(shù)都是需要各種參數(shù)才能運(yùn)行的,這些參數(shù)組成的集合就稱為上下文。

  • Flask中的上下文

變量名 上下文 說(shuō)明
current_app 程序上下文 當(dāng)前激活程序的程序?qū)嵗?/td>
g 程序上下文 上下文全局變量
request 請(qǐng)求上下文 請(qǐng)求對(duì)象,封裝了客戶端發(fā)出的HTTP請(qǐng)求中的內(nèi)容
session 請(qǐng)求上下文 用戶會(huì)話,用戶儲(chǔ)存同一個(gè)客戶端在多個(gè)請(qǐng)求間需要“記住”的信息
  • 請(qǐng)求上下文

請(qǐng)求上下文變量是在視圖函數(shù)被觸發(fā)時(shí)傳入的一個(gè)HTTP請(qǐng)求對(duì)象,儲(chǔ)存了所有客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù),因此該變量只有在視圖函數(shù)中才能訪問(wèn)。如果難以理解,你只需要記住request變量只有在視圖函數(shù)中才能訪問(wèn)
我們可以通過(guò)以下方式引入請(qǐng)求上下文變量:

from flask import request
  • 請(qǐng)求上下文變量常用的訪問(wèn)操作有:

    request.args 獲取所有GET請(qǐng)求參數(shù)
    request.form 獲取所有form-data、x-www-form-urlencoded類型的請(qǐng)求參數(shù)
    request.json 獲取所有json類型的請(qǐng)求參數(shù)
    request.method 獲取請(qǐng)求方法
    request.headers 獲取請(qǐng)求頭

  • 請(qǐng)求鉤子

    • 什么是鉤子(Hook)?
      打個(gè)比方,魚鉤是用來(lái)釣魚的,一旦魚咬了鉤,鉤子就一直鉤住魚了,任憑魚在水里怎么游,也逃不出魚鉤的控制。在程序設(shè)計(jì)里,鉤子就是一個(gè)事件,鉤住了某段代碼,任憑這段代碼這么運(yùn)行,都逃不過(guò)我的鉤子事件。

    • Flask里的請(qǐng)求鉤子

      鉤子 說(shuō)明
      before_first_request 注冊(cè)一個(gè)函數(shù),在處理第一個(gè)請(qǐng)求之前運(yùn)行
      before_request 注冊(cè)一個(gè)函數(shù),在每次請(qǐng)求之前運(yùn)行
      after_request 注冊(cè)一個(gè)函數(shù),如果沒(méi)有未處理的異常拋出,在每次請(qǐng)求之后運(yùn)行
      teardown_request 注冊(cè)一個(gè)函數(shù),即使有未處理的異常拋出,也在每次請(qǐng)求之后運(yùn)行
    • 用法

    from flask import request
    
    @app.before_request
    def app_before_request():
        print("HTTP {}  {}".format(request.method, request.url))
    

    這樣在每次請(qǐng)求時(shí)都會(huì)輸出請(qǐng)求方式和請(qǐng)求url,但其實(shí)鉤子函數(shù)的作用遠(yuǎn)不止這些。

  • 響應(yīng)

    通常,每個(gè)視圖函數(shù)都有返回值,而最簡(jiǎn)單的就是一串字符串了,F(xiàn)lask默認(rèn)返回的類型是text/html,狀態(tài)碼為200。狀態(tài)碼很重要,如果需要修改,我們可以這樣做:

    @app.route("/")
    def hello_word():
        return "Not Found", 404
    

    當(dāng)然,如果要自定義響應(yīng),最好還是引入make_response函數(shù),該函數(shù)接受一個(gè)bytes對(duì)象(二進(jìn)制數(shù)據(jù))或者字符串作為響應(yīng)主體,并返回一個(gè)響應(yīng)對(duì)象response,通過(guò)這個(gè)對(duì)象我們可以自定義該響應(yīng)的頭部,比如修改響應(yīng)頭部的Content-Type和Content-Disposition來(lái)告訴客戶端這個(gè)文件是需要被下載的,并且將From設(shè)置為Ncuhome來(lái)告訴客戶端該文件來(lái)自家園工作室。

    @app.route("/download")
    def download():
      response = make_response(open("lesson.md", "rb").read())
      response.headers["From"] = "Ncuhome"
      response.headers["Content-Type"] = "application/octet-stream; charset=utf-8;"
      response.headers["Content-Disposition"] = "attachment;filename=lesson.md"
      return response
    
  • 快速構(gòu)建一個(gè)json格式的響應(yīng)

    前后端交互時(shí),一般都是使用JSON格式數(shù)據(jù)進(jìn)行交互

    from flask import jsonify
    @app.route('/hello', methods=['GET'])
    def user(user_id):
        if not user_id == 1:
            abort(404)
    
        return jsonify({
            "status": 1,
            "data": {
                "username": "ncuhome",
                "desc": "Hello, Ncuhomer!",
            },
            "message": "獲取成功"
        })
    
  • 其他一些響應(yīng)

    • 重定向
    from flask import redirect
    @app.route("/ncuos")
    def ncuos():
        return redirect("https://www.ncuos.com/")
    
    • 重定向到某個(gè)路由
    from flask import url_for
    @app.route("/redirect_to_hello")
    def redirect():
        return redirect(url_for("hello"))
    
    @app.route("/hello")
    def hello():
        return "Hello, Ncuhomer!"
    
    • 返回HTTP狀態(tài)碼
    from flask import abort
    @app.route("/user/<int:user_id>")
    def get_user(user_id):
        abort(404)
    

Jinja2 模板引擎

前面提到了Jinja2,它的作用其實(shí)是為了方便構(gòu)造HTML文檔、以及其他的一些文檔內(nèi)容(郵件等)。

  • 響應(yīng)返回完整HTML
    簡(jiǎn)單舉個(gè)栗子吧
    模板文件 ./template/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ncuhome Demo</title>
    </head>
    <body>
        Hello, {{ name }}
    </body>
    </html>
    
    其中name就是我們需要填補(bǔ)的,它用花括號(hào){{ }}括起來(lái)了。
    填補(bǔ)name并返回完整HTML:
     from flask import render_template
     @app.route("/hello/<string:name>")
     def hello(name):
         return render_template("index.html", name=name)
    
  • 模板中的for循環(huán)
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ncuhome Demo</title>
    </head>
    <body>
      {% for user in users %}
      {{ loop.index }}: {{ user }} <br>
      {% endfor %}
    </body>
    </html>
    
     from flask import render_template
     @app.route("/users")
     def hello(name):
         users = ["Amy", "David", "Sam"]
         return render_template("index.html", users=users)
    
  • 模板中的if
    if和for類似,都擁有一個(gè)作用域,用法也一樣。
    {% if name %}
       {{ name }}
    {% endif %}
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容