python flask框架詳解

Flask是一個Python編寫的Web 微框架,讓我們可以使用Python語言快速實現一個網站或Web服務。本文參考自Flask官方文檔
英文不好的同學也可以參考中文文檔

1.安裝flask

pip install flask

2.簡單上手

一個最小的 Flask 應用如下:

from flask import Flask
app = Flask(__name__)

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

if __name__ == '__main__':
   app.run()

代碼解析:
1、首先我們導入了 Flask 類。 該類的實例將會成為我們的 WSGI 應用。
2、接着我們創建一個該類的實例。第一個參數是應用模塊或者包的名稱。如果你使用 一個單一模塊(就像本例),那麼應當使用 name ,因為名稱會根據這個 模塊是按應用方式使用還是作為一個模塊導入而發生變化(可能是 『main』 , 也可能是實際導入的名稱)。這個參數是必需的,這樣 Flask 才能知道在哪裡可以 找到模板和靜態文件等東西
3、然後我們使用 route() 裝飾器來告訴 Flask 觸發函數的 URL 。
4、函數名稱被用於生成相關聯的 URL 。函數最後返回需要在用戶瀏覽器中顯示的信息。

運行結果:

* Serving Flask app "flask_demo" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on //127.0.0.1:5000/ (Press CTRL+C to quit)

訪問://127.0.0.1:5000/
在這裡插入圖片描述

app.route(rule, options)
  • rule 參數表示與該函數的URL綁定。
  • options 是要轉發給基礎Rule對象的參數列表。
    在上面的示例中,’/ ‘ URL與hello_world()函數綁定。因此,當在瀏覽器中打開web服務器的主頁時,將呈現該函數的輸出。
    最後,Flask類的run()方法在本地開發服務器上運行應用程序。
app.run(host, port, debug, options)

所有參數都是可選的

  • host:要監聽的主機名。 默認為127.0.0.1(localhost)。設置為「0.0.0.0」以使服務器在外部可用
  • port :默認值為5000
  • debug:默認為false。 如果設置為true,則提供調試信息,可以自動重載代碼並顯示調試信息
  • options:要轉發到底層的Werkzeug服務器。

2.1 調試模式

雖然 flask 命令可以方便地啟動一個本地開發服務器,但是每次應用代碼 修改之後都需要手動重啟服務器。這樣不是很方便, Flask 可以做得更好。如果你打開 調試模式,那麼服務器會在修改應用代碼之後自動重啟,並且當應用出錯時還會提供一個 有用的調試器。
在命令行中,如果需要打開所有開發功能(包括調試模式),那麼要在運行服務器之前導出 FLASK_ENV 環境變量並把其設置為 development:

$ export FLASK_ENV=development
$ flask run

在代碼中,在運行或將調試參數傳遞給run()方法之前,通過將application對象的debug屬性設置為True來啟用Debug模式。

app.debug = True
app.run()
# 或者
app.run(debug = True)

2.2 綁定IP和端口

默認情況下,Flask綁定IP為127.0.0.1,端口為5000。我們也可以通過下面的方式自定義:

app.run(host='0.0.0.0', port=80, debug=True)

0.0.0.0代表電腦所有的IP。80是HTTP網站服務的默認端口。什麼是默認?比如,我們訪問網站//www.example.com,其實是訪問的//www.example.com:80,只不過:80可以省略不寫。

3.Flask 路由

現代Web框架使用路由技術來幫助用戶記住應用程序URL。可以直接訪問所需的頁面,而無需從主頁導航。

Flask中的route()裝飾器用於將URL綁定到函數。例如:

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

在這裡,URL'/ hello'規則綁定到hello_world()函數。 因此,如果用戶訪問//localhost:5000/hello URL,hello_world()函數的輸出將在瀏覽器中呈現。

application對象的add_url_rule()函數也可用於將URL與函數綁定,如上例所示,使用route()裝飾器的目的也由以下表示:

def hello_world():
   return 'hello world'
app.add_url_rule('/', 'hello', hello_world)

4.Flask 變量規則

通過向規則參數添加變量部分,可以動態構建URL。此變量部分標記為 <converter:variable_name>。它作為關鍵字參數傳遞給與規則相關聯的函數。
在以下示例中,route()裝飾器的規則參數包含附加到URL'/hello'<name>。 因此,如果在瀏覽器中輸入//localhost:5000/hello/chenshifeng作為URL,則’chenshifeng’將作為參數提供給 hello()函數。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:flask_demo.py
@time:2021/03/01
"""
from flask import Flask

app = Flask(__name__)


@app.route('/hello/<name>')
def hello_name(name):
    return 'Hello %s!' % name


if __name__ == '__main__':
    app.run(debug=True)

運行,訪問://localhost:5000/hello/chenshifeng
在這裡插入圖片描述
除了默認字符串變量部分之外,還可以使用以下轉換器構建規則:

轉換器 描述
string (缺省值) 接受任何不包含斜杠的文本
int 接受正整數
float 接受正浮點數
path 類似 string ,但可以包含斜杠
uuid 接受 UUID 字符串
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:flask_demo.py
@time:2021/03/01
"""
from flask import Flask

app = Flask(__name__)


@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id


@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % subpath


if __name__ == '__main__':
    app.run(debug=True)

在這裡插入圖片描述
在這裡插入圖片描述

4.1唯一的 URL / 重定向行為

以下兩條規則的不同之處在於是否使用尾部的斜杠。:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

projects 的 URL 是中規中矩的,尾部有一個斜杠,看起來就如同一個文件夾。 訪問一個沒有斜杠結尾的 URL 時 Flask 會自動進行重定向,幫你在尾部加上一個斜杠。

about 的 URL 沒有尾部斜杠,因此其行為表現與一個文件類似。如果訪問這個 URL 時添加了尾部斜杠就會得到一個 404 錯誤。這樣可以保持 URL 唯一,並幫助 搜索引擎避免重複索引同一頁面。

5.Flask URL構建

url_for()函數對於動態構建特定函數的URL非常有用。該函數接受函數的名稱作為第一個參數,以及一個或多個關鍵字參數,每個參數對應於URL的變量部分。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:flask_demo.py
@time:2021/03/01
"""
from flask import Flask, redirect, url_for

app = Flask(__name__)


@app.route('/admin')
def hello_admin():
    return 'Hello Admin'


@app.route('/guest/<guest>')
def hello_guest(guest):
    return 'Hello %s as Guest' % guest


@app.route('/user/<name>')
def hello_user(name):
    if name == 'admin':
        return redirect(url_for('hello_admin'))
    else:
        return redirect(url_for('hello_guest', guest=name))


if __name__ == '__main__':
    app.run(debug=True)

redirect函數用於重定向,實現機制很簡單,就是向客戶端(瀏覽器)發送一個重定向的HTTP報文,瀏覽器會去訪問報文中指定的url。

運行
打開瀏覽器並輸入URL – //localhost:5000/user/admin

Hello Admin

在瀏覽器中輸入以下URL – //localhost:5000/user/mvl

Hello mvl as Guest

6.Flask HTTP方法

Web 應用使用不同的 HTTP 方法處理 URL 。當你使用 Flask 時,應當熟悉 HTTP 方法。 缺省情況下,一個路由只回應 GET 請求。 可以使用 route() 裝飾器的 methods 參數來處理不同的 HTTP 方法:

方法 描述
GET 以未加密的形式將數據發送到服務器,最常見的方法。
HEAD 和GET方法相同,但沒有響應體。
POST 用於將HTML表單數據發送到服務器,POST方法接收的數據不由服務器緩存。
PUT 用上傳的內容替換目標資源的所有當前表示。
DELETE 刪除由URL給出的目標資源的所有當前表示。

默認情況下,Flask路由響應GET請求。但是,可以通過為route()裝飾器提供方法參數來更改此首選項。

為了演示在URL路由中使用POST方法,首先讓我們創建一個HTML表單,並使用POST方法將表單數據發送到URL。
將以下腳本另存為login.html

<html>
   <body>
      
      <form action = "//localhost:5000/login" method = "post">
         <p>Enter Name:</p>
         <p><input type = "text" name = "nm" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
      
   </body>
</html>

運行以下代碼

from flask import Flask, redirect, url_for, request
app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
   return 'welcome %s' % name

@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST':
      user = request.form['nm']
      return redirect(url_for('success',name = user))
   else:
      user = request.args.get('nm')
      return redirect(url_for('success',name = user))

if __name__ == '__main__':
   app.run(debug = True)

在瀏覽器中打開login.html,在文本字段中輸入name,然後單擊提交。
在這裡插入圖片描述
表單數據將POST到表單標籤的action子句中的URL。

//localhost/login映射到login()函數。由於服務器通過POST方法接收數據,因此通過以下步驟獲得從表單數據獲得的「nm」參數的值:
表單數據將POST到表單標籤的action子句中的URL。

user = request.form['nm']

它作為變量部分傳遞給’/ success’ URL。瀏覽器在窗口中顯示welcome消息。
在這裡插入圖片描述
在login.html中將方法參數更改為’GET’,然後在瀏覽器中再次打開它。服務器上接收的數據是通過GET方法獲得的。通過以下的步驟獲得’nm’參數的值:

User = request.args.get('nm')

這裡,args是包含表單參數對及其對應值對的列表的字典對象。與’nm’參數對應的值將像之前一樣傳遞到’/ success’ URL。

7.Flask 模板

在大型應用中,把業務邏輯和表現內容放在一起,會增加代碼的複雜度和維護成本.

  • 模板其實是一個包含響應文本的文件,其中用佔位符(變量)表示動態部分,告訴模板引擎其具體的值需要從使用的數據中獲取
  • 使用真實值替換變量,再返回最終得到的字符串,這個過程稱為’渲染’
  • Flask 是使用 Jinja2 這個模板引擎來渲染模板

使用模板的好處

  • 視圖函數只負責業務邏輯和數據處理(業務邏輯方面)
  • 而模板則取到視圖函數的數據結果進行展示(視圖展示方面)
  • 代碼結構清晰,耦合度低

使用 render_template() 方法可以渲染模板,你只要提供模板名稱和需要 作為參數傳遞給模板的變量就行了。
Flask 會在 templates 文件夾內尋找模板。因此,如果你的應用是一個模塊, 那麼模板文件夾應該在模塊旁邊;如果是一個包,那麼就應該在包裏面:
情形 1 : 一個模塊:

/application.py
/templates
    /hello.html

情形 2 : 一個包:

/application
    /__init__.py
    /templates
        /hello.html

示例代碼:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    my_int = 18
    my_str = 'curry'
    my_list = [1, 5, 4, 3, 2]
    my_dict = {
        'name': 'durant',
        'age': 28
    }

    # render_template方法:渲染模板
    # 參數1: 模板名稱  參數n: 傳到模板里的數據
    return render_template('hello.html',
                           my_int=my_int,
                           my_str=my_str,
                           my_list=my_list,
                           my_dict=my_dict)


if __name__ == '__main__':
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>

<body>
  <h2>我是模板</h2>
  {{ my_int }}
  <br>
  {{ my_str }}
  <br>
  {{ my_list }}
  <br>
  {{ my_dict }}
  <hr>
  <h2>模板的list數據獲取</h2>
  <hr>
  {{ my_list[0] }}
  <br>
  {{ my_list.1 }}
  <hr>
  <h2>字典數據獲取</h2>
  <hr>
  {{ my_dict['name'] }}
  <br>
  {{ my_dict.age }}
  <hr>
  <h2>算術運算</h2>
  <br>
  {{ my_list.0 + 10 }}
  <br>
  {{ my_list[0] + my_list.1 }}
</body>

</html>

運行效果:
在這裡插入圖片描述

8.Flask 靜態文件

動態的 web 應用也需要靜態文件,一般是 CSS 和 JavaScript 文件。理想情況下你的 服務器已經配置好了為你的提供靜態文件的服務。但是在開發過程中, Flask 也能做好 這項工作。只要在你的包或模塊旁邊創建一個名為 static 的文件夾就行了。 靜態文件位於應用的 /static 中。
使用特定的 ‘static’ 端點就可以生成相應的 URL

url_for('static', filename='style.css')

這個靜態文件在文件系統中的位置應該是 static/style.css 。

在下面的示例中,在index.html中的HTML按鈕的OnClick事件上調用hello.js中定義的javascript函數,該函數在Flask應用程序的「/」URL上呈現。

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def index():
   return render_template("index.html")

if __name__ == '__main__':
   app.run(debug = True)

index.html的HTML腳本如下所示:

<html>

   <head>
      <script type = "text/javascript"
         src = "{{ url_for('static', filename = 'hello.js') }}" ></script>
   </head>

   <body>
      <input type = "button" onclick = "sayHello()" value = "Say Hello" />
   </body>

</html>

Hello.js包含sayHello()函數。

function sayHello() {
   alert("Hello World")
}

運行效果:
在這裡插入圖片描述

9.Flask Request對象

來自客戶端網頁的數據作為全局請求對象發送到服務器。為了處理請求數據,應該從Flask模塊導入。

Request對象的重要屬性如下所列:

  • form – 它是一個字典對象,包含表單參數及其值的鍵和值對。
  • args – 解析查詢字符串的內容,它是問號(?)之後的URL的一部分。
  • Cookies – 保存Cookie名稱和值的字典對象。
  • files – 與上傳文件有關的數據。
  • method – 當前請求方法

首先,你必須從 flask 模塊導入請求對象:

from flask import request

9.1 Flask 將表單數據發送到模板

我們已經看到,可以在 URL 規則中指定 http 方法。觸發函數接收的 Form 數據可以以字典對象的形式收集它並將其轉發到模板以在相應的網頁上呈現它。

在以下示例中,’/’ URL 會呈現具有表單的網頁(student.html)。填入的數據會發佈到觸發 result() 函數的 ‘/result’ URL。

result() 函數收集字典對象中的 request.form 中存在的表單數據,並將其發送給 result.html。

該模板動態呈現表單數據的 HTML 表格。

下面給出的是應用程序的 Python 代碼:

from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def student():
   return render_template('student.html')


@app.route('/result',methods = ['POST', 'GET'])
def result():
   if request.method == 'POST':
      result = request.form
      return render_template("result.html",result = result)


if __name__ == '__main__':
   app.run(debug = True)

下面給出的是 student.html 的 HTML 腳本。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <form action="//localhost:5000/result" method="POST">
     <p>Name <input type = "text" name = "Name" /></p>
     <p>Physics <input type = "text" name = "Physics" /></p>
     <p>Chemistry <input type = "text" name = "chemistry" /></p>
     <p>Maths <input type ="text" name = "Mathematics" /></p>
     <p><input type = "submit" value = "submit" /></p>
  </form>
</body>
</html>

下面給出了模板( result.html )的代碼:

<!doctype html>
  <table border = 1>
     {% for key, value in result.items() %}
    <tr>
       <th> {{ key }} </th>
       <td> {{ value }}</td>
    </tr>
 {% endfor %}
</table>

運行效果:
運行 Python 腳本,並在瀏覽器中輸入 URL //localhost:5000/。
在這裡插入圖片描述當點擊提交按鈕時,表單數據以 HTML 表格的形式呈現在 result.html 上。
在這裡插入圖片描述

9.2 Flask Cookies

Cookie以文本文件的形式存儲在客戶端的計算機上。其目的是記住和跟蹤與客戶使用相關的數據,以獲得更好的訪問者體驗和網站統計信息。

Request對象包含Cookie的屬性。它是所有cookie變量及其對應值的字典對象,客戶端已傳輸。除此之外,cookie還存儲其網站的到期時間,路徑和域名。
在Flask中,對cookie的處理步驟為:

  1. 設置cookie:
    設置cookie,默認有效期是臨時cookie,瀏覽器關閉就失效
    可以通過 max_age 設置有效期, 單位是秒
 resp = make_response("success")   # 設置響應體
 resp.set_cookie("chenshifeng", "shifengboy", max_age=3600)
  1. 獲取cookie
    獲取cookie,通過request.cookies的方式, 返回的是一個字典,可以獲取字典里的相應的值
cookie_1 = request.cookies.get("chenshifeng")
  1. 刪除cookie
    這裡的刪除只是讓cookie過期,並不是直接刪除cookie
    刪除cookie,通過delete_cookie()的方式, 裏面是cookie的名字
resp = make_response("del success")  # 設置響應體
resp.delete_cookie("chenshifeng")

以下為Flask Cookies的簡單示例:

from flask import Flask, make_response, request

app = Flask(__name__)

@app.route("/set_cookies")
def set_cookie():
    resp = make_response("success")
    resp.set_cookie("chenshifeng", "shifengboy",max_age=3600)
    return resp

@app.route("/get_cookies")
def get_cookie():
    cookie_1 = request.cookies.get("chenshifeng")  # 獲取名字為Itcast_1對應cookie的值
    return cookie_1

@app.route("/delete_cookies")
def delete_cookie():
    resp = make_response("del success")
    resp.delete_cookie("chenshifeng")

    return resp

if __name__ == '__main__':
    app.run(debug=True)

設置cookies

運行應用程序,在瀏覽器中輸入 127.0.0.1:5000/set_cookies 來設置cookies,設置 cookies 的輸出如下所示:
在這裡插入圖片描述
獲取cookie
根據視圖函數中相對應的路徑,輸入 //127.0.0.1:5000/get_cookies ,讀回 cookies 的輸出如下所示:
在這裡插入圖片描述

刪除cookie
根據視圖函數中相對應的路徑,輸入 //127.0.0.1:5000/delete_cookies ,刪除 cookies 的輸出如下所示:
在這裡插入圖片描述

注意刪除,只是讓 cookie 過期。

10.Flask 會話

與Cookie不同,Session(會話)數據存儲在服務器上。會話是客戶端登錄到服務器並註銷服務器的時間間隔。需要在該會話中保存的數據會存儲在服務器上的臨時目錄中。

為每個客戶端的會話分配會話ID。會話數據存儲在cookie的頂部,服務器以加密方式對其進行簽名。對於此加密,Flask應用程序需要一個定義的SECRET_KEY。

Session對象也是一個字典對象,包含會話變量和關聯值的鍵值對。

例如,要設置一個’username’會話變量,請使用以下語句:

Session['username'] = 'admin'

要釋放會話變量,請使用pop()方法。

session.pop('username', None)

演示代碼:


from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)

app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'  # 確保設置應用程序的secret_key


@app.route('/')
def index():
    if 'username' in session:
        username = session['username']

        return '登錄用戶名是:' + username + '<br>' + \
               "<b><a href = '/logout'>點擊這裡註銷</a></b>"

    return "您暫未登錄, <br><a href = '/login'></b>" + \
           "點擊這裡登錄</b></a>"


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']

        return redirect(url_for('index'))

    return '''

   <form action = "" method = "post">

      <p><input type ="text" name ="username"/></p>

      <p><input type ="submit" value ="登錄"/></p>

   </form>

   '''


@app.route('/logout')
def logout():
    # remove the username from the session if it is there

    session.pop('username', None)

    return redirect(url_for('index'))


if __name__ == '__main__':
    app.run(debug=True)

如何生成一個好的密鑰
生成隨機數的關鍵在於一個好的隨機種子,因此一個好的密鑰應當有足夠的隨機性。 操作系統可以有多種方式基於密碼隨機生成器來生成隨機數據。使用下面的命令 可以快捷的為 Flask.secret_key ( 或者 SECRET_KEY )生成值:
$ python -c ‘import os; print(os.urandom(16))’
b’_5#y2L”F4Q8z\n\xec]/’

訪問//127.0.0.1:5000/,只是提示用戶登錄,因為未設置會話變量’username’。
在這裡插入圖片描述
當用戶點擊登錄,瀏覽到「/login」login()視圖函數時,因為它是通過GET方法調用的,所以將打開一個登錄表單。
在這裡插入圖片描述

點擊登錄,通過POST方法將表單發送回’/login’,現在會話變量已設置。應用程序重定向到’/’。此時會話變量’username’被找到。
在這裡插入圖片描述
應用程序還包含一個logout()視圖函數,它會彈出’username’會話變量。因此,’/’ URL再次顯示開始頁面。
在這裡插入圖片描述

11.Flask 重定向和錯誤

Flask類有一個redirect()函數。調用時,它返回一個響應對象,並將用戶重定向到具有指定狀態代碼的另一個目標位置。

redirect()函數的原型如下:

Flask.redirect(location, statuscode, response)

在上述函數中:

  • location參數是應該重定向響應的URL。
  • statuscode發送到瀏覽器標頭,默認為302。
  • response參數用於實例化響應。

以下狀態代碼已標準化:

  • HTTP_300_MULTIPLE_CHOICES
  • HTTP_301_MOVED_PERMANENTLY
  • HTTP_302_FOUND
  • HTTP_303_SEE_OTHER
  • HTTP_304_NOT_MODIFIED
  • HTTP_305_USE_PROXY
  • HTTP_306_RESERVED
  • HTTP_307_TEMPORARY_REDIRECT

默認狀態代碼為302,表示’found’。
在以下示例中,redirect()函數用於在登錄嘗試失敗時再次顯示登錄頁面。

from flask import Flask, redirect, url_for, render_template, request

# Initialize the Flask application
app = Flask(__name__)


@app.route('/')
def index():
    return render_template('log_in.html')


@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST' and request.form['username'] == 'admin':
        return redirect(url_for('success'))
    return redirect(url_for('index'))


@app.route('/success')
def success():
    return 'logged in successfully'


if __name__ == '__main__':
    app.run(debug=True)

下面給出的是 log_in.html的 HTML 腳本。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
      <form action = "//localhost:5000/login" method = "POST">
         <p>Enter Name:</p>
         <p><input type = "text" name = "username" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
</body>
</html>

Flask類具有帶有錯誤代碼的abort()函數。

Flask.abort(code)

Code參數採用以下值之一:

  • 400 – 用於錯誤請求
  • 401 – 用於未身份驗證的
  • 403 – Forbidden
  • 404 – 未找到
  • 406 – 表示不接受
  • 415 – 用於不支持的媒體類型
  • 429 – 請求過多
    讓我們對上述代碼中的login()函數稍作更改。如果要顯示’Unauthurized’頁面,請將其替換為調用abort(401),而不是重新顯示登錄頁面。
from flask import Flask, redirect, url_for, render_template, request, abort

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('log_in.html')


@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        if request.form['username'] == 'admin':
            return redirect(url_for('success'))
        else:
            abort(401)
    else:
        return redirect(url_for('index'))


@app.route('/success')
def success():
    return 'logged in successfully'


if __name__ == '__main__':
    app.run(debug=True)

運行,輸入非admin的用戶名,點擊提交
在這裡插入圖片描述

12. Flask 消息閃現

一個好的基於 GUI 的應用程序會向用戶提供有關交互的反饋。例如,桌面應用程序使用對話框或消息框,JavaScript 使用警報用於類似目的。

在 Flask Web 應用程序中生成這樣的信息性消息很容易。Flask 框架的閃現系統可以在一個視圖中創建消息,並在名為 next 的視圖函數中呈現它。

Flask 模塊包含 flash() 方法。它將消息傳遞給下一個請求,該請求通常是一個模板。

flash(message, category)

其中,

  • message 參數是要閃現的實際消息。
  • category 參數是可選的。它可以是「error」,「info」或「warning」。
    為了從會話中獲取消息,模板調用 get_flashed_messages()。
    以下是一個完整的示例:
from flask import Flask, flash, redirect, render_template, \
     request, url_for

app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'admin' or \
           request.form['password'] != 'secret':
            error = 'Invalid credentials'
        else:
            flash('You were successfully logged in')
            return redirect(url_for('index'))
    return render_template('login.html', error=error)

if __name__ == '__main__':
    app.run(debug=True)

以下是實現閃現的 layout.html 模板:

<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
{% block body %}{% endblock %}

以下是繼承自 layout.html 的 index.html 模板:

{% block body %}
  <h1>Overview</h1>
  <p>Do you want to <a href="{{ url_for('login') }}">log in?</a>
{% endblock %}

以下是同樣繼承自 layout.html 的 login.html 模板:

{% extends "layout.html" %}
{% block body %}
  <h1>Login</h1>
  {% if error %}
    <p class=error><strong>Error:</strong> {{ error }}
  {% endif %}
  <form method=post>
    <dl>
      <dt>Username:
      <dd><input type=text name=username value="{{
          request.form.username }}">
      <dt>Password:
      <dd><input type=password name=password>
    </dl>
    <p><input type=submit value=Login>
  </form>
{% endblock %}

運行
首頁
在這裡插入圖片描述
登錄報錯頁
在這裡插入圖片描述
登錄成功頁
在這裡插入圖片描述

13. Flask 文件上傳

在 Flask 中處理文件上傳非常簡單。它需要一個 HTML 表單,其 ​enctype​ 屬性設置為'multipart/form-data​',將文件發佈到 URL。URL 處理程序從 ​request.files[]​ 對象中提取文件,並將其保存到所需的位置。

每個上傳的文件首先會保存在服務器上的臨時位置,然後將其實際保存到它的最終位置。目標文件的名稱可以是硬編碼的,也可以從 ​request.files[file] ​對象的​filename​屬性中獲取。但是,建議使用 ​secure_filename()​ 函數獲取它的安全版本。
可以在 Flask 對象的配置設置中定義默認上傳文件夾的路徑和上傳文件的最大大小。

app.config[『UPLOAD_FOLDER』] 定義上傳文件夾的路徑 app.config[『MAX_CONTENT_LENGTH』] 指定要上傳的文件的最大大小(以位元組為單位)

以下代碼具有 ​'/upload' ​URL 規則,該規則在 templates 文件夾中顯示​ 'upload.html'​,以及 ​'/ upload-file' ​URL 規則,用於調用 ​uploader() ​函數處理上傳過程。
​'upload.html' ​有一個文件選擇器按鈕和一個提交按鈕。

<html>
<head>
  <title>File Upload</title>
</head>
<body>
    <form action="//localhost:5000/uploader" method="POST" enctype="multipart/form-data">
        <input type="file" name="file" accept=".jpg,.png" />
        <input type="submit" />
    </form>
</body>
</html>

以下是 Flask 應用程序的 Python 代碼。

from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = '/Users/chenshifeng/upload/'

@app.route('/upload')
def upload_file():
   return render_template('upload.html')

@app.route('/uploader', methods = ['GET', 'POST'])
def uploader():
   if request.method == 'POST':
      f = request.files['file']
      f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename)))
      return 'file uploaded successfully'

if __name__ == '__main__':
   app.run()

您將看到如下所示的界面。
在這裡插入圖片描述
選擇文件後,單擊提交。表單的​ post ​方法調用​ '/ upload_file'​ URL。底層函數 ​uploader()​ 執行保存操作。
上傳成功會顯示以下畫面:
在這裡插入圖片描述
上傳文件被放到/Users/chenshifeng/upload文件夾下:
在這裡插入圖片描述

14. Flask 擴展

Flask通常被稱為微框架,因為核心功能包括基於Werkzeug的WSGI和路由以及基於Jinja2的模板引擎。此外,Flask框架還支持cookie和會話,以及JSON,靜態文件等Web幫助程序。顯然,這不足以開發完整的Web應用程序。而Flask擴展就具備這樣的功能。Flask擴展為Flask框架提供了可擴展性。

有大量的Flask擴展可用。Flask擴展是一個Python模塊,它向Flask應用程序添加了特定類型的支持。Flask Extension Registry(Flask擴展註冊表)是一個可用的擴展目錄。可以通過pip實用程序下載所需的擴展名。

在本教程中,我們將討論以下重要的Flask擴展:

  • Flask Mail – 為Flask應用程序提供SMTP接口
  • Flask WTF – 添加WTForms的渲染和驗證
  • Flask SQLAlchemy – 為Flask應用程序添加SQLAlchemy支持
  • Flask Sijax – Sijax的接口 – Python/jQuery庫,使AJAX易於在Web應用程序中使用

每種類型的擴展通常提供有關其用法的大量文檔。由於擴展是一個Python模塊,因此需要導入它才能使用它。Flask擴展名通常命名為flask-foo。導入的操作如下:

from flask_foo import [class, function]

對於0.7以後的Flask版本,您還可以使用語法:

from flask.ext import foo

對於此用法,需要激活兼容性模塊。它可以通過運行flaskext_compat.py來安裝:

import flaskext_compat
flaskext_compat.activate()
from flask.ext import foo

14.1 Flask 郵件

務器建立簡單的接口變得非常容易。

首先,應該在pip實用程序的幫助下安裝Flask-Mail擴展。

pip install Flask-Mail

然後需要通過設置以下應用程序參數的值來配置Flask-Mail。

參數 描述
MAIL_SERVER 電子郵件服務器的名稱/IP地址
MAIL_PORT 使用的服務器的端口號
MAIL_USE_TLS 啟用/禁用傳輸安全層加密
MAIL_USE_SSL 啟用/禁用安全套接字層加密
MAIL_DEBUG 調試支持。默認值是Flask應用程序的調試狀態
MAIL_USERNAME 發件人的用戶名
MAIL_PASSWORD 發件人的密碼
MAIL_DEFAULT_SENDER 設置默認發件人
MAIL_MAX_EMAILS 設置要發送的最大郵件數
MAIL_SUPPRESS_SEND 如果app.testing設置為true,則發送被抑制
MAIL_ASCII_ATTACHMENTS 如果設置為true,則附加的文件名將轉換為ASCII

flask-mail模塊包含以下重要類的定義。

14.1.1 Mail類

它管理電子郵件消息傳遞需求。類構造函數採用以下形式:

flask-mail.Mail(app = None)

構造函數將Flask應用程序對象作為參數。
Mail類的方法:

方法 描述
send() 發送Message類對象的內容
connect() 打開與郵件主機的連接
send_message() 發送消息對象

14.1.2 Message類

它封裝了一封電子郵件。Message類構造函數有幾個參數:

flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, reply-to, date, charset, extra_headers, mail_options,rcpt_options)

Message類方法:

  • attach() – 為郵件添加附件。此方法採用以下參數:

    • filename – 要附加的文件的名稱
    • content_type – MIME類型的文件
    • data – 原始文件數據
    • 處置 – 內容處置(如果有的話)。
  • add_recipient() – 向郵件添加另一個收件人

在下面的示例中,使用QQ郵箱服務的SMTP服務器用作Flask-Mail配置的MAIL_SERVER。

from flask import Flask
from flask_mail import Mail, Message

app =Flask(__name__)
mail=Mail(app)

app.config['MAIL_SERVER']='smtp.qq.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = '[email protected]'
app.config['MAIL_PASSWORD'] = 'xxxxxxxx'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)

@app.route("/")
def index():
   msg = Message('Hello', sender = '[email protected]', recipients = ['[email protected]'])
   msg.body = "Hello Flask message sent from Flask-Mail"
   mail.send(msg)
   return "Sent"

if __name__ == '__main__':
   app.run(debug = True)

在這裡插入圖片描述

15. Flask SQLAlchemy

步驟1 – 安裝Flask-SQLAlchemy擴展。

pip install flask-sqlalchemy

步驟2 – 您需要從此模塊導入SQLAlchemy類。

from flask_sqlalchemy import SQLAlchemy

步驟3 – 現在創建一個Flask應用程序對象並為要使用的數據庫設置URI。

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'

步驟4 – 然後使用應用程序對象作為參數創建SQLAlchemy類的對象。該對象包含用於ORM操作的輔助函數。它還提供了一個父Model類,使用它來聲明用戶定義的模型。在下面的代碼段中,創建了students模型。

db = SQLAlchemy(app)
class students(db.Model):
   id = db.Column('student_id', db.Integer, primary_key = True)
   name = db.Column(db.String(100))
   city = db.Column(db.String(50))  
   addr = db.Column(db.String(200))
   pin = db.Column(db.String(10))

def __init__(self, name, city, addr,pin):
   self.name = name
   self.city = city
   self.addr = addr
   self.pin = pin

步驟5 – 要創建/使用URI中提及的數據庫,請運行create_all()方法。

db.create_all()

SQLAlchemy的Session對象管理ORM對象的所有持久性操作。
以下session方法執行CRUD操作:

  • db.session.add (模型對象) – 將記錄插入到映射表中
  • db.session.delete (模型對象) – 從表中刪除記錄
  • model.query.all() – 從表中檢索所有記錄(對應於SELECT查詢)。
    您可以通過使用filter屬性將過濾器應用於檢索到的記錄集。例如,要在學生表中檢索city =’Hyderabad’的記錄,請使用以下語句:
Students.query.filter_by(city = 』Hyderabad』).all()

有了這麼多的背景,現在我們將為我們的應用程序提供視圖函數來添加學生數據。

應用程序的入口點是綁定到’/’ URL的show_all()函數。學生表的記錄集作為參數發送到HTML模板。模板中的服務器端代碼以HTML表格形式呈現記錄。

@app.route('/')
def show_all():
   return render_template('show_all.html', students = students.query.all() )

模板(’show_all.html’)的HTML腳本如下:

<!DOCTYPE html>
<html lang = "en">
   <head></head>
   <body>
      
      <h3>
         <a href = "{{ url_for('show_all') }}">Comments - Flask 
            SQLAlchemy example</a>
      </h3>
      
      <hr/>
      {%- for message in get_flashed_messages() %}
         {{ message }}
      {%- endfor %}
		
      <h3>Students (<a href = "{{ url_for('new') }}">Add Student
         </a>)</h3>
      
      <table>
         <thead>
            <tr>
               <th>Name</th>
               <th>City</th>
               <th>Address</th>
               <th>Pin</th>
            </tr>
         </thead>
         
         <tbody>
            {% for student in students %}
               <tr>
                  <td>{{ student.name }}</td>
                  <td>{{ student.city }}</td>
                  <td>{{ student.addr }}</td>
                  <td>{{ student.pin }}</td>
               </tr>
            {% endfor %}
         </tbody>
      </table>
      
   </body>
</html>

上述網頁包含指向’/ new’ URL映射new()函數的超鏈接。單擊時,將打開「學生信息」表單。 數據在 POST方法中發佈到相同的URL。
new.html

<!DOCTYPE html>
<html>
   <body>
   
      <h3>Students - Flask SQLAlchemy example</h3>
      <hr/>
      
      {%- for category, message in get_flashed_messages(with_categories = true) %}
         <div class = "alert alert-danger">
            {{ message }}
         </div>
      {%- endfor %}
      
      <form action = "{{ request.path }}" method = "post">
         <label for = "name">Name</label><br>
         <input type = "text" name = "name" placeholder = "Name" /><br>
         <label for = "email">City</label><br>
         <input type = "text" name = "city" placeholder = "city" /><br>
         <label for = "addr">addr</label><br>
         <textarea name = "addr" placeholder = "addr"></textarea><br>
         <label for = "PIN">PINCODE</label><br>
         <input type = "text" name = "pin" placeholder = "pin" /><br>
         <input type = "submit" value = "Submit" />
      </form>
      
   </body>
</html>

當http方法被檢測為POST時,表單數據被添加到學生表中,並且應用返回到顯示添加數據的主頁。

@app.route('/new', methods = ['GET', 'POST'])
def new():
   if request.method == 'POST':
      if not request.form['name'] or not request.form['city'] or not request.form['addr']:
         flash('Please enter all the fields', 'error')
      else:
         student = students(request.form['name'], request.form['city'],
            request.form['addr'], request.form['pin'])
         
         db.session.add(student)
         db.session.commit()
         
         flash('Record was successfully added')
         return redirect(url_for('show_all'))
   return render_template('new.html')

下面給出了應用程序(app.py)的完整代碼。

from flask import Flask, request, flash, url_for, redirect, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'
app.config['SECRET_KEY'] = "random string"

db = SQLAlchemy(app)


class students(db.Model):
    id = db.Column('student_id', db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    city = db.Column(db.String(50))
    addr = db.Column(db.String(200))
    pin = db.Column(db.String(10))


    def __init__(self, name, city, addr, pin):
        self.name = name
        self.city = city
        self.addr = addr
        self.pin = pin


@app.route('/')
def show_all():
    return render_template('show_all.html', students=students.query.all())


@app.route('/new', methods=['GET', 'POST'])
def new():
    if request.method == 'POST':
        if not request.form['name'] or not request.form['city'] or not request.form['addr']:
            flash('Please enter all the fields', 'error')
        else:
            student = students(request.form['name'], request.form['city'],
                               request.form['addr'], request.form['pin'])

            db.session.add(student)
            db.session.commit()
            flash('Record was successfully added')
            return redirect(url_for('show_all'))
    return render_template('new.html')


if __name__ == '__main__':
    db.create_all()
    app.run(debug=True)

首頁
在這裡插入圖片描述
錯誤頁:
在這裡插入圖片描述
提交成功頁:
在這裡插入圖片描述
本文參考://www.w3cschool.cn/flask/