Flask 快速指南



Flask – 概述

什麼是Web框架?

Web應用程式框架,簡稱Web框架,代表著一組庫和模組,使Web應用程式開發人員能夠編寫應用程式,而無需處理低階細節,例如協議、執行緒管理等。

什麼是Flask?

Flask是一個用Python編寫的Web應用程式框架。它由Armin Ronacher開發,他領導著一個名為Pocco的國際Python愛好者團隊。Flask基於Werkzeug WSGI工具包和Jinja2模板引擎。兩者都是Pocco專案。

WSGI

Web伺服器閘道器介面(WSGI)已被採用為Python Web應用程式開發的標準。WSGI是Web伺服器和Web應用程式之間通用介面的規範。

Werkzeug

它是一個WSGI工具包,實現了請求、響應物件和其他實用程式函式。這使得可以在其之上構建Web框架。Flask框架使用Werkzeug作為其基礎之一。

Jinja2

Jinja2是Python的一個流行模板引擎。Web模板系統將模板與某個資料來源結合起來,以呈現動態網頁。

Flask通常被稱為微框架。它旨在保持應用程式的核心簡單但可擴充套件。Flask沒有內建的資料庫處理抽象層,也沒有表單驗證支援。相反,Flask支援擴充套件以嚮應用程式新增此類功能。本教程後面將討論一些流行的Flask擴充套件。

Flask – 環境配置

先決條件

安裝Flask通常需要Python 2.6或更高版本。雖然Flask及其依賴項可以與Python 3(Python 3.3及更高版本)很好地配合使用,但許多Flask擴充套件並不完全支援它。因此,建議在Python 2.7上安裝Flask。

安裝virtualenv用於開發環境

virtualenv是一個虛擬Python環境構建器。它幫助使用者並排建立多個Python環境。因此,它可以避免不同版本的庫之間的相容性問題。

以下命令安裝virtualenv

pip install virtualenv

此命令需要管理員許可權。在Linux/Mac OS上,在pip之前新增sudo。如果您使用的是Windows,請以管理員身份登入。在Ubuntu上,可以使用其包管理器安裝virtualenv

Sudo apt-get install virtualenv

安裝完成後,新的虛擬環境將建立在一個資料夾中。

mkdir newproj
cd newproj
virtualenv venv

要在Linux/OS X上啟用相應的環境,請使用以下命令:

venv/bin/activate

Windows上,可以使用以下命令:

venv\scripts\activate

現在我們可以準備在這個環境中安裝Flask了。

pip install Flask

以上命令可以直接執行,無需虛擬環境即可進行系統範圍的安裝。

Flask – 應用程式

為了測試Flask安裝,請在編輯器中將以下程式碼鍵入為Hello.py

from flask import Flask
app = Flask(__name__)

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

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

在專案中匯入flask模組是必須的。Flask類的物件是我們的WSGI應用程式。

Flask建構函式將當前模組(__name__)的名稱作為引數。

Flask類的route()函式是一個裝飾器,它告訴應用程式哪個URL應該呼叫關聯的函式。

app.route(rule, options)
  • rule引數表示URL與函式的繫結。

  • options是轉發到底層Rule物件的引數列表。

在上面的示例中,‘/’ URL繫結到hello_world()函式。因此,當在瀏覽器中開啟Web伺服器的主頁時,將呈現此函式的輸出。

最後,Flask類的run()方法在本地開發伺服器上執行應用程式。

app.run(host, port, debug, options)

所有引數都是可選的

序號 引數和描述
1

host

要監聽的主機名。預設為127.0.0.1(localhost)。設定為‘0.0.0.0’以使伺服器可從外部訪問

2

port

預設為5000

3

debug

預設為false。如果設定為true,則提供除錯資訊

4

options

轉發到底層Werkzeug伺服器。

以上給出的Python指令碼是從Python shell執行的。

Python Hello.py

Python shell中的訊息通知您

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

在瀏覽器中開啟上面的URL(localhost:5000)。將顯示‘Hello World’訊息。

除錯模式

透過呼叫run()方法啟動Flask應用程式。但是,在應用程式開發過程中,應該為程式碼中的每次更改手動重新啟動它。為了避免這種不便,啟用除錯支援。如果程式碼發生更改,伺服器將重新載入自身。如果應用程式中存在任何錯誤,它還將提供一個有用的偵錯程式來跟蹤這些錯誤。

透過在執行前將application物件的debug屬性設定為True或將debug引數傳遞給run()方法來啟用Debug模式。

app.debug = True
app.run()
app.run(debug = True)

Flask – 路由

現代Web框架使用路由技術來幫助使用者記住應用程式URL。它有助於直接訪問所需頁面,而無需從主頁導航。

Flask中的route()裝飾器用於將URL繫結到函式。例如:

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

這裡,URL‘/hello’規則繫結到hello_world()函式。因此,如果使用者訪問https://:5000/hello URL,則hello_world()函式的輸出將在瀏覽器中呈現。

應用程式物件的add_url_rule()函式也可用於將URL與函式繫結,如上例所示,使用了route()

裝飾器的目的也由以下表示法提供:

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

Flask – 變數規則

可以透過向rule引數新增可變部分來動態構建URL。此可變部分標記為<variable-name>。它作為關鍵字引數傳遞給與該規則關聯的函式。

在下面的示例中,route()裝飾器的rule引數包含附加到URL‘/hello’的可變部分<name>。因此,如果在瀏覽器中輸入https://:5000/hello/TutorialsPoint作為URL,則‘TutorialPoint’將作為引數提供給hello()函式。

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)

將上述指令碼儲存為hello.py並從Python shell執行它。接下來,開啟瀏覽器並輸入URLhttps://:5000/hello/TutorialsPoint

瀏覽器將顯示以下輸出:

Hello TutorialsPoint!

除了預設的字串變數部分外,還可以使用以下轉換器構建規則:

序號 轉換器和描述
1

int

接受整數

2

float

用於浮點值

3

path

接受用作目錄分隔符的斜槓

在以下程式碼中,使用了所有這些構造器。

from flask import Flask
app = Flask(__name__)

@app.route('/blog/<int:postID>')
def show_blog(postID):
   return 'Blog Number %d' % postID

@app.route('/rev/<float:revNo>')
def revision(revNo):
   return 'Revision Number %f' % revNo

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

從Python Shell執行上述程式碼。在瀏覽器中訪問URLhttps://:5000/blog/11

給定的數字用作show_blog()函式的引數。瀏覽器顯示以下輸出:

Blog Number 11

在瀏覽器中輸入此URL:https://:5000/rev/1.1

revision()函式將浮點數作為引數。以下結果出現在瀏覽器視窗中:

Revision Number 1.100000

Flask的URL規則基於Werkzeug的路由模組。這確保了生成的URL是唯一的,並且基於Apache制定的先例。

考慮以下指令碼中定義的規則:

from flask import Flask
app = Flask(__name__)

@app.route('/flask')
def hello_flask():
   return 'Hello Flask'

@app.route('/python/')
def hello_python():
   return 'Hello Python'

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

這兩個規則看起來相似,但在第二個規則中,使用了尾部斜槓(/)。結果,它成為規範URL。因此,使用/python/python/返回相同的輸出。但是,對於第一個規則,/flask/ URL會導致404 Not Found頁面。

Flask – URL構建

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

以下指令碼演示了url_for()函式的使用。

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)

上述指令碼有一個函式user(name),它從URL接收值作為其引數。

User()函式檢查接收到的引數是否與‘admin’匹配。如果匹配,則使用url_for()將應用程式重定向到hello_admin()函式,否則將接收到的引數作為guest引數傳遞給hello_guest()函式。

儲存上述程式碼並從Python shell執行。

開啟瀏覽器並輸入URL為:https://:5000/user/admin

瀏覽器中的應用程式響應為:

Hello Admin

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

應用程式響應現在更改為:

Hello mvl as Guest

Flask – HTTP 方法

Http協議是全球資訊網中資料通訊的基礎。此協議中定義了從指定URL檢索資料的不同方法。

下表總結了不同的http方法:

序號 方法和描述
1

GET

以未加密的形式將資料傳送到伺服器。最常見的方法。

2

HEAD

與GET相同,但沒有響應正文

3

POST

用於將HTML表單資料傳送到伺服器。伺服器不會快取POST方法接收到的資料。

4

PUT

用上傳的內容替換目標資源的所有當前表示。

5

DELETE

刪除URL給出的目標資源的所有當前表示

預設情況下,Flask路由響應GET請求。但是,可以透過向route()裝飾器提供methods引數來更改此首選項。

為了演示在URL路由中使用POST方法,讓我們首先建立一個HTML表單,並使用POST方法將表單資料傳送到URL。

將以下指令碼儲存為login.html

<html>
   <body>
      <form action = "https://: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>

現在在Python shell中輸入以下指令碼。

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,在文字欄位中輸入名稱,然後單擊Submit

Post Method Example

表單資料POST到表單標記的action子句中的URL。

https:///login對映到login()函式。由於伺服器已透過POST方法接收到資料,因此從表單資料中獲得的‘nm’引數的值透過以下方式獲得:

user = request.form['nm']

它作為可變部分傳遞到‘/success’ URL。瀏覽器在視窗中顯示歡迎訊息。

Welcome Message

login.html中將method引數更改為‘GET’,然後在瀏覽器中再次開啟它。伺服器接收到的資料是透過GET方法接收的。‘nm’引數的值現在透過以下方式獲得:

User = request.args.get(‘nm’)

這裡,args是包含表單引數及其對應值對列表的字典物件。與‘nm’引數對應的值像以前一樣傳遞到‘/success’ URL。

Flask – 模板

可以以HTML的形式返回繫結到特定URL的函式的輸出。例如,在以下指令碼中,hello()函式將呈現‘Hello World’,並附加<h1>標記。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
   return '<html><body><h1>Hello World</h1></body></html>'

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

但是,從Python程式碼生成HTML內容很麻煩,尤其是在需要新增可變資料和Python語言元素(如條件或迴圈)時。這將需要頻繁地從HTML轉義。

這裡可以利用Flask所基於的Jinja2模板引擎。與其從函式中返回硬編碼的HTML,不如使用render_template()函式渲染HTML檔案。

from flask import Flask
app = Flask(__name__)

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

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

Flask 將嘗試在模板資料夾中查詢HTML檔案,該資料夾與包含此指令碼的資料夾位於同一目錄下。

  • 應用程式資料夾
    • Hello.py
    • templates
      • hello.html

術語“Web模板系統”指的是設計一個HTML指令碼,其中可以動態插入可變資料。Web模板系統由模板引擎、某種資料來源和模板處理器組成。

Flask使用Jinja2模板引擎。Web模板包含HTML語法,其中穿插著變數和表示式的佔位符(在本例中為Python表示式),這些佔位符在渲染模板時會被替換為值。

以下程式碼儲存在templates資料夾中的hello.html檔案中。

<!doctype html>
<html>
   <body>
   
      <h1>Hello {{ name }}!</h1>
      
   </body>
</html>

接下來,從Python shell執行以下指令碼。

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

@app.route('/hello/<user>')
def hello_name(user):
   return render_template('hello.html', name = user)

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

當開發伺服器啟動並執行後,開啟瀏覽器並輸入URL:https://:5000/hello/mvl

URL中的變數部分插入到{{ name }}佔位符中。

Web Templating System Example

Jinja2模板引擎使用以下定界符來轉義HTML。

  • {% ... %} 用於語句
  • {{ ... }} 用於列印到模板輸出的表示式
  • {# ... #} 用於模板輸出中不包含的註釋
  • # ... ## 用於行語句

在以下示例中,演示了在模板中使用條件語句。到hello()函式的URL規則接受整數引數。它被傳遞到hello.html模板。在其中,比較接收到的數值(分數)(大於或小於50),並根據此結果有條件地渲染HTML。

Python指令碼如下:

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

@app.route('/hello/<int:score>')
def hello_name(score):
   return render_template('hello.html', marks = score)

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

hello.html的HTML模板指令碼如下:

<!doctype html>
<html>
   <body>
      {% if marks>50 %}
         <h1> Your result is pass!</h1>
      {% else %}
         <h1>Your result is fail</h1>
      {% endif %}
   </body>
</html>

請注意,條件語句if-elseendif包含在定界符{%..%}中。

執行Python指令碼並訪問URL https:///hello/60,然後訪問https:///hello/30,檢視HTML輸出根據條件變化。

Python迴圈結構也可以在模板內使用。在以下指令碼中,當在瀏覽器中開啟URL https://:5000/result時,result()函式將字典物件傳送到模板results.html

result.html的模板部分使用for迴圈將字典物件result{}的鍵值對渲染為HTML表格的單元格。

從Python shell執行以下程式碼。

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

@app.route('/result')
def result():
   dict = {'phy':50,'che':60,'maths':70}
   return render_template('result.html', result = dict)

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

將以下HTML指令碼儲存為templates資料夾中的result.html

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

這裡,與For迴圈相對應的Python語句再次包含在{%..%}中,而表示式key和value則放在{{ }}內。

開發伺服器啟動並執行後,在瀏覽器中開啟https://:5000/result,即可獲得以下輸出。

Table Template Example

Flask – 靜態檔案

Web應用程式通常需要靜態檔案,例如支援網頁顯示的javascript檔案或CSS檔案。通常,Web伺服器會配置為您提供服務,但在開發過程中,這些檔案是從包中的static資料夾或模組旁邊的static資料夾提供的服務,它在應用程式中可用/static

一個特殊的端點“static”用於生成靜態檔案的URL。

在以下示例中,在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")
}

Flask – 請求物件

來自客戶端網頁的資料作為全域性請求物件傳送到伺服器。為了處理請求資料,應從Flask模組匯入它。

請求物件的重要屬性如下:

  • Form – 包含表單引數及其值的鍵值對的字典物件。

  • args – 解析後的查詢字串內容,它是問號(?)之後URL的一部分。

  • Cookies – 儲存Cookie名稱和值的字典物件。

  • files – 與上傳檔案相關的資料。

  • method – 當前請求方法。

Flask – 將表單資料傳送到模板

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

在以下示例中,‘/’ URL呈現一個包含表單的網頁(student.html)。其中填寫的資料被髮布到‘/result’ URL,該URL觸發result()函式。

results()函式收集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指令碼。

<html>
   <body>
      <form action = "https://: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>
<html>
   <body>
      <table border = 1>
         {% for key, value in result.items() %}
            <tr>
               <th> {{ key }} </th>
               <td> {{ value }} </td>
            </tr>
         {% endfor %}
      </table>
   </body>
</html>

執行Python指令碼並在瀏覽器中輸入URL https://:5000/

Submit Marks

單擊提交按鈕時,表單資料將以HTML表格的形式在result.html上呈現。

Marks Table

Flask – Cookies

Cookie以文字檔案的形式儲存在客戶端的計算機上。其目的是記住和跟蹤與客戶端使用相關的資料,以獲得更好的訪客體驗和網站統計資料。

請求物件包含Cookie的屬性。它是客戶端已傳輸的所有Cookie變數及其對應值的字典物件。此外,Cookie還儲存其過期時間、路徑和站點的域名。

在Flask中,Cookie是在響應物件上設定的。使用make_response()函式從檢視函式的返回值獲取響應物件。之後,使用響應物件的set_cookie()函式儲存Cookie。

讀取Cookie很容易。request.cookies屬性的get()方法用於讀取Cookie。

在以下Flask應用程式中,當您訪問‘/’ URL時,會開啟一個簡單的表單。

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

此HTML頁面包含一個文字輸入。

<html>
   <body>
      <form action = "/setcookie" method = "POST">
         <p><h3>Enter userID</h3></p>
         <p><input type = 'text' name = 'nm'/></p>
         <p><input type = 'submit' value = 'Login'/></p>
      </form>
   </body>
</html>

表單釋出到‘/setcookie’ URL。關聯的檢視函式設定一個名為userID的Cookie並呈現另一個頁面。

@app.route('/setcookie', methods = ['POST', 'GET'])
def setcookie():
   if request.method == 'POST':
   user = request.form['nm']
   
   resp = make_response(render_template('readcookie.html'))
   resp.set_cookie('userID', user)
   
   return resp

‘readcookie.html’包含指向另一個檢視函式getcookie()的超連結,該函式讀取並顯示瀏覽器中的Cookie值。

@app.route('/getcookie')
def getcookie():
   name = request.cookies.get('userID')
   return '<h1>welcome '+name+'</h1>'

執行應用程式並訪問https://:5000/

ReadCookie HTML

設定Cookie的結果顯示如下:

Result of Setting Cookie

讀取Cookie的輸出如下所示。

Reading Cookie Back

Flask – 會話

與Cookie類似,會話資料儲存在客戶端。會話是指客戶端登入伺服器並登出伺服器的時間間隔。在此會話期間需要保留的資料儲存在客戶端瀏覽器中。

為每個客戶端分配一個會話ID。會話資料儲存在Cookie之上,伺服器會對其進行加密簽名。對於這種加密,Flask應用程式需要定義一個SECRET_KEY

會話物件也是一個字典物件,包含會話變數及其關聯值的鍵值對。

例如,要設定‘username’會話變數,請使用以下語句:

Session[‘username’] = ’admin’

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

session.pop('username', None)

以下程式碼是Flask中會話工作的一個簡單演示。URL ‘/’只是提示使用者登入,因為會話變數‘username’未設定。

@app.route('/')
def index():
   if 'username' in session:
      username = session['username']
         return 'Logged in as ' + username + '<br>' + \
         "<b><a href = '/logout'>click here to log out</a></b>"
   return "You are not logged in <br><a href = '/login'></b>" + \
      "click here to log in</b></a>"

當用戶瀏覽到‘/login’時,login()檢視函式(因為它透過GET方法呼叫)會開啟一個登入表單。

表單回發到‘/login’,現在會話變數已設定。應用程式將重定向到‘/’。這次找到了會話變數‘username’

@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 = Login/></p>
   </form>
	
   '''

應用程式還包含一個logout()檢視函式,該函式彈出‘username’會話變數。因此,‘/’ URL再次顯示開啟頁面。

@app.route('/logout')
def logout():
   # remove the username from the session if it is there
   session.pop('username', None)
   return redirect(url_for('index'))

執行應用程式並訪問主頁。(確保設定應用程式的secret_key

from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.secret_key = 'any random string’

輸出將如下所示。單擊連結“點選此處登入”

Login Page Using Session

連結將指向另一個螢幕。鍵入‘admin’。

Another Login Screen

螢幕將顯示訊息“已登入為admin”

Logged in as admin

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,表示“已找到”

在以下示例中,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'))
   else:
      return redirect(url_for('index'))

@app.route('/success')
def success():
   return 'logged in successfully'
	
if __name__ == '__main__':
   app.run(debug = True)

Flask類具有帶有錯誤程式碼的abort()函式。

Flask.abort(code)

Code引數採用以下值之一:

  • 400 – 用於錯誤請求

  • 401 – 用於未經身份驗證

  • 403 – 用於禁止訪問

  • 404 – 用於未找到

  • 406 – 用於不可接受

  • 415 – 用於不支援的媒體型別

  • 429 – 請求過多

讓我們對上述程式碼中的login()函式做一個小小的修改。如果要顯示“未授權”頁面,而不是重新顯示登入頁面,請將其替換為對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)

Flask – 訊息閃現

一個良好的基於GUI的應用程式會向用戶提供有關互動的反饋。例如,桌面應用程式使用對話方塊或訊息框,而JavaScript使用警報來實現類似的目的。

在Flask Web應用程式中生成此類資訊性訊息很容易。Flask框架的閃現系統使得可以在一個檢視中建立訊息,並在接下來呼叫的檢視函式中呈現它。

Flask模組包含flash()方法。它將訊息傳遞到下一個請求,通常是模板。

flash(message, category)

這裡:

  • message引數是要閃現的實際訊息。

  • category引數是可選的。它可以是“error”、“info”或“warning”。

為了從會話中刪除訊息,模板呼叫get_flashed_messages()

get_flashed_messages(with_categories, category_filter)

這兩個引數都是可選的。如果接收到的訊息具有類別,則第一個引數是一個元組。第二個引數用於僅顯示特定訊息。

以下閃現訊息使用了模板。

{% with messages = get_flashed_messages() %}
   {% if messages %}
      {% for message in messages %}
         {{ message }}
      {% endfor %}
   {% endif %}
{% endwith %}

現在讓我們看一個簡單的例子,演示Flask中的閃現機制。在下面的程式碼中,‘/’ URL顯示登入頁面的連結,沒有閃現任何訊息。

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

此連結引導使用者進入‘/login’ URL,該URL顯示登入表單。提交後,login()檢視函式將驗證使用者名稱和密碼,並相應地閃現‘success’訊息或建立‘error’變數。

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

如果出現error,則會重新顯示登入模板以及錯誤訊息。

Login.html

<!doctype html>
<html>
   <body>
      <h1>Login</h1>

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

另一方面,如果登入成功,則會在索引模板上閃現成功訊息。

Index.html

<!doctype html>
<html>
   <head>
      <title>Flask Message flashing</title>
   </head>
   <body>
      {% with messages = get_flashed_messages() %}
         {% if messages %}
            <ul>
               {% for message in messages %}
               <li<{{ message }}</li>
               {% endfor %}
            </ul>
         {% endif %}
      {% endwith %}
		
      <h1>Flask Message Flashing Example</h1>
      <p>Do you want to <a href = "{{ url_for('login') }}">
         <b>log in?</b></a></p>
   </body>
</html>

下面給出了Flask訊息閃現示例的完整程式碼:

Flash.py

from flask import Flask, flash, redirect, render_template, request, url_for
app = Flask(__name__)
app.secret_key = 'random string'

@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'] != 'admin':
         error = 'Invalid username or password. Please try again!'
      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)

執行上述程式碼後,您將看到如下所示的螢幕。

Flask Message Flashing Example

單擊連結後,您將被定向到登入頁面。

輸入使用者名稱和密碼。

Login Page

單擊登入。將顯示一條訊息“您已成功登入”。

Successfully Logged in Page

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規則,該規則顯示模板資料夾中的‘upload.html’,以及‘/upload-file’ URL規則,該規則呼叫處理上傳過程的uploader()函式。

‘upload.html’有一個檔案選擇器按鈕和一個提交按鈕。

<html>
   <body>
      <form action = "https://:5000/uploader" method = "POST" 
         enctype = "multipart/form-data">
         <input type = "file" name = "file" />
         <input type = "submit"/>
      </form>
   </body>
</html>

您將看到如下所示的螢幕。

Flask File Uploading

選擇檔案後單擊提交。表單的post方法呼叫‘/upload_file’ URL。底層函式uploader()執行儲存操作。

以下是Flask應用程式的Python程式碼。

from flask import Flask, render_template, request
from werkzeug import secure_filename
app = Flask(__name__)

@app.route('/upload')
def upload_file():
   return render_template('upload.html')
	
@app.route('/uploader', methods = ['GET', 'POST'])
def upload_file():
   if request.method == 'POST':
      f = request.files['file']
      f.save(secure_filename(f.filename))
      return 'file uploaded successfully'
		
if __name__ == '__main__':
   app.run(debug = True)

Flask – 擴充套件

Flask通常被稱為微框架,因為其核心功能包括基於Werkzeug的WSGI和路由以及基於Jinja2的模板引擎。此外,Flask框架還支援cookie和會話以及諸如JSON、靜態檔案等的Web輔助工具。顯然,這不足以開發一個成熟的Web應用程式。這就是Flask擴充套件發揮作用的地方。Flask擴充套件為Flask框架提供了可擴充套件性。

有很多可用的Flask擴充套件。Flask擴充套件是一個Python模組,它為Flask應用程式新增特定型別的支援。Flask擴充套件登錄檔是一個可用的擴充套件目錄。可以使用pip實用程式下載所需的擴充套件。

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

  • Flask Mail − 為Flask應用程式提供SMTP介面

  • Flask WTF − 新增WTForms的渲染和驗證

  • Flask SQLAlchemy − 為Flask應用程式新增SQLAlchemy支援

  • Flask Sijax − Sijax的介面 - 一個Python/jQuery庫,使在Web應用程式中易於使用AJAX

每種型別的擴充套件通常都提供關於其用法的廣泛文件。由於擴充套件是一個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

Flask – 郵件

基於Web的應用程式通常需要具有向用戶/客戶端傳送郵件的功能。Flask-Mail擴充套件使得使用任何電子郵件伺服器設定簡單的介面變得非常容易。

首先,應使用pip實用程式安裝Flask-Mail擴充套件。

pip install Flask-Mail

然後,需要透過設定以下應用程式引數的值來配置Flask-Mail。

序號 引數和描述
1

MAIL_SERVER

電子郵件伺服器的名稱/IP地址

2

MAIL_PORT

使用的伺服器埠號

3

MAIL_USE_TLS

啟用/停用傳輸安全層加密

4

MAIL_USE_SSL

啟用/停用安全套接字層加密

5

MAIL_DEBUG

除錯支援。預設為Flask應用程式的除錯狀態

6

MAIL_USERNAME

發件人的使用者名稱

7

MAIL_PASSWORD

發件人的密碼

8

MAIL_DEFAULT_SENDER

設定預設發件人

9

MAIL_MAX_EMAILS

設定要傳送的最大郵件數

10

MAIL_SUPPRESS_SEND

如果app.testing設定為true,則抑制傳送

11

MAIL_ASCII_ATTACHMENTS

如果設定為true,則附加檔名將轉換為ASCII

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

Mail類

它管理電子郵件訊息要求。類的建構函式採用以下形式:

flask-mail.Mail(app = None)

建構函式將Flask應用程式物件作為引數。

Mail類的使用方法

序號 方法和描述
1

send()

傳送Message類物件的內容

2

connect()

開啟與郵件主機的連線

3

send_message()

傳送訊息物件

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 − 原始檔案資料

  • disposition − 內容處置(如有)。

add_recipient() − 向訊息新增另一個收件人

在以下示例中,Google的gmail服務的SMTP伺服器用作Flask-Mail配置的MAIL_SERVER。

步驟1 − 在程式碼中從flask-mail模組匯入Mail和Message類。

from flask_mail import Mail, Message

步驟2 − 然後根據以下設定配置Flask-Mail。

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True

步驟3 − 建立Mail類的例項。

mail = Mail(app)

步驟4 − 在由URL規則(‘/’)對映的Python函式中設定Message物件。

@app.route("/")
def index():
   msg = Message('Hello', sender = 'yourId@gmail.com', recipients = ['id1@gmail.com'])
   msg.body = "This is the email body"
   mail.send(msg)
   return "Sent"

步驟5 − 完整的程式碼如下所示。在Python Shell中執行以下指令碼,然後訪問https://:5000/

from flask import Flask
from flask_mail import Mail, Message

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

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)

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

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

請注意,Gmail服務中的內建安全功能可能會阻止此登入嘗試。您可能需要降低安全級別。請登入您的Gmail帳戶並訪問連結以降低安全性。

Decrease the Security

Flask – WTF

Web應用程式的一個重要方面是為使用者提供使用者介面。HTML提供了一個<form>標籤,用於設計介面。可以適當地使用表單元素,例如文字輸入、單選按鈕、選擇等。

使用者輸入的資料以Http請求訊息的形式透過GET或POST方法提交到伺服器端指令碼。

  • 伺服器端指令碼必須從http請求資料中重新建立表單元素。因此,實際上,表單元素必須定義兩次——一次在HTML中,另一次在伺服器端指令碼中。

  • 使用HTML表單的另一個缺點是很難(如果不是不可能的話)動態渲染表單元素。HTML本身不提供任何驗證使用者輸入的方法。

這就是WTForms(一個靈活的表單、渲染和驗證庫)發揮作用的地方。Flask-WTF擴充套件為此WTForms庫提供了一個簡單的介面。

使用Flask-WTF,我們可以在Python指令碼中定義表單欄位,並使用HTML模板渲染它們。也可以對WTF欄位應用驗證。

讓我們看看這個HTML的動態生成是如何工作的。

首先,需要安裝Flask-WTF擴充套件。

pip install flask-WTF

已安裝的包包含一個Form類,該類必須用作使用者定義表單的父類。

WTforms包包含各種表單欄位的定義。一些標準表單欄位列在下面。

序號 標準表單欄位和說明
1

TextField

表示<input type = 'text'> HTML表單元素

2

BooleanField

表示<input type = 'checkbox'> HTML表單元素

3

DecimalField

用於顯示帶有小數的數字的文字欄位

4

IntegerField

用於顯示整數的文字欄位

5

RadioField

表示<input type = 'radio'> HTML表單元素

6

SelectField

表示select表單元素

7

TextAreaField

表示<textarea> html表單元素

8

PasswordField

表示<input type = 'password'> HTML表單元素

9

SubmitField

表示<input type = 'submit'> 表單元素

例如,包含文字欄位的表單可以設計如下:

from flask_wtf import Form
from wtforms import TextField

class ContactForm(Form):
   name = TextField("Name Of Student")

除了‘name’欄位外,還會自動建立一個用於CSRF令牌的隱藏欄位。這是為了防止跨站點請求偽造攻擊。

渲染後,這將生成如下所示的等效HTML指令碼。

<input id = "csrf_token" name = "csrf_token" type = "hidden" />
<label for = "name">Name Of Student</label><br>
<input id = "name" name = "name" type = "text" value = "" />

使用者定義的表單類用於Flask應用程式中,並且使用模板渲染表單。

from flask import Flask, render_template
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'development key'

@app.route('/contact')
def contact():
   form = ContactForm()
   return render_template('contact.html', form = form)

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

WTForms包還包含validator類。它可用於對錶單欄位應用驗證。以下列表顯示了常用的驗證器。

序號 驗證器類和說明
1

DataRequired

檢查輸入欄位是否為空

2

Email

檢查欄位中的文字是否符合電子郵件ID約定

3

IPAddress

驗證輸入欄位中的IP地址

4

Length

驗證輸入欄位中字串的長度是否在給定範圍內

5

NumberRange

驗證輸入欄位中給定範圍內的數字

6

URL

驗證輸入欄位中輸入的URL

我們現在將為聯絡表單中的name欄位應用‘DataRequired’驗證規則。

name = TextField("Name Of Student",[validators.Required("Please enter your name.")])

表單物件的validate()函式驗證表單資料,如果驗證失敗則丟擲驗證錯誤。錯誤訊息被髮送到模板。在HTML模板中,錯誤訊息是動態渲染的。

{% for message in form.name.errors %}
   {{ message }}
{% endfor %}

以下示例演示了上述概念。聯絡表單的設計如下所示(forms.py)

from flask_wtf import Form
from wtforms import TextField, IntegerField, TextAreaField, SubmitField, RadioField,
   SelectField

from wtforms import validators, ValidationError

class ContactForm(Form):
   name = TextField("Name Of Student",[validators.Required("Please enter 
      your name.")])
   Gender = RadioField('Gender', choices = [('M','Male'),('F','Female')])
   Address = TextAreaField("Address")
   
   email = TextField("Email",[validators.Required("Please enter your email address."),
      validators.Email("Please enter your email address.")])
   
   Age = IntegerField("age")
   language = SelectField('Languages', choices = [('cpp', 'C++'), 
      ('py', 'Python')])
   submit = SubmitField("Send")

驗證器應用於姓名電子郵件欄位。

以下是Flask應用程式指令碼(formexample.py)

from flask import Flask, render_template, request, flash
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'development key'

@app.route('/contact', methods = ['GET', 'POST'])
def contact():
   form = ContactForm()
   
   if request.method == 'POST':
      if form.validate() == False:
         flash('All fields are required.')
         return render_template('contact.html', form = form)
      else:
         return render_template('success.html')
      elif request.method == 'GET':
         return render_template('contact.html', form = form)

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

模板指令碼(contact.html)如下所示:

<!doctype html>
<html>
   <body>
      <h2 style = "text-align: center;">Contact Form</h2>
		
      {% for message in form.name.errors %}
         <div>{{ message }}</div>
      {% endfor %}
      
      {% for message in form.email.errors %}
         <div>{{ message }}</div>
      {% endfor %}
      
      <form action = "https://:5000/contact" method = post>
         <fieldset>
            <legend>Contact Form</legend>
            {{ form.hidden_tag() }}
            
            <div style = font-size:20px; font-weight:bold; margin-left:150px;>
               {{ form.name.label }}<br>
               {{ form.name }}
               <br>
               
               {{ form.Gender.label }} {{ form.Gender }}
               {{ form.Address.label }}<br>
               {{ form.Address }}
               <br>
               
               {{ form.email.label }}<br>
               {{ form.email }}
               <br>
               
               {{ form.Age.label }}<br>
               {{ form.Age }}
               <br>
               
               {{ form.language.label }}<br>
               {{ form.language }}
               <br>
               {{ form.submit }}
            </div>
            
         </fieldset>
      </form>
   </body>
</html>

在Python shell中執行formexample.py並訪問URLhttps://:5000/contact聯絡表單將顯示如下。

Form Example

如果出現任何錯誤,頁面將如下所示:

Form Error Page

如果沒有錯誤,將呈現‘success.html’

Form Success Page

Flask – SQLite

Python內建支援SQlite。SQLite3模組隨Python發行版一起提供。有關在Python中使用SQLite資料庫的詳細教程,請參閱此連結。在本節中,我們將瞭解Flask應用程式如何與SQLite互動。

建立一個SQLite資料庫‘database.db’並在其中建立一個學生表。

import sqlite3

conn = sqlite3.connect('database.db')
print "Opened database successfully";

conn.execute('CREATE TABLE students (name TEXT, addr TEXT, city TEXT, pin TEXT)')
print "Table created successfully";
conn.close()

我們的Flask應用程式具有三個檢視函式。

第一個new_student()函式繫結到URL規則(‘/addnew’)。它呈現一個包含學生資訊表單的HTML檔案。

@app.route('/enternew')
def new_student():
   return render_template('student.html')

‘student.html’的HTML指令碼如下所示:

<html>
   <body>
      <form action = "{{ url_for('addrec') }}" method = "POST">
         <h3>Student Information</h3>
         Name<br>
         <input type = "text" name = "nm" /></br>
         
         Address<br>
         <textarea name = "add" ></textarea><br>
         
         City<br>
         <input type = "text" name = "city" /><br>
         
         PINCODE<br>
         <input type = "text" name = "pin" /><br>
         <input type = "submit" value = "submit" /><br>
      </form>
   </body>
</html>

如您所見,表單資料釋出到繫結addrec()函式的‘/addrec’ URL。

addrec()函式透過POST方法檢索表單資料並將其插入學生表中。插入操作成功或失敗的訊息將呈現到‘result.html’

@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
   if request.method == 'POST':
      try:
         nm = request.form['nm']
         addr = request.form['add']
         city = request.form['city']
         pin = request.form['pin']
         
         with sql.connect("database.db") as con:
            cur = con.cursor()
            cur.execute("INSERT INTO students (name,addr,city,pin) 
               VALUES (?,?,?,?)",(nm,addr,city,pin) )
            
            con.commit()
            msg = "Record successfully added"
      except:
         con.rollback()
         msg = "error in insert operation"
      
      finally:
         return render_template("result.html",msg = msg)
         con.close()

result.html的HTML指令碼包含一個轉義語句{{msg}},該語句顯示插入操作的結果。

<!doctype html>
<html>
   <body>
      result of addition : {{ msg }}
      <h2><a href = "\">go back to home page</a></h2>
   </body>
</html>

該應用程式包含另一個由‘/list’ URL表示的list()函式。它將rows填充為包含學生表中所有記錄的MultiDict物件。此物件傳遞給list.html模板。

@app.route('/list')
def list():
   con = sql.connect("database.db")
   con.row_factory = sql.Row
   
   cur = con.cursor()
   cur.execute("select * from students")
   
   rows = cur.fetchall(); 
   return render_template("list.html",rows = rows)

list.html是一個模板,它迭代行集並在HTML表中呈現資料。

<!doctype html>
<html>
   <body>
      <table border = 1>
         <thead>
            <td>Name</td>
            <td>Address>/td<
            <td>city</td>
            <td>Pincode</td>
         </thead>
         
         {% for row in rows %}
            <tr>
               <td>{{row["name"]}}</td>
               <td>{{row["addr"]}}</td>
               <td> {{ row["city"]}}</td>
               <td>{{row['pin']}}</td>	
            </tr>
         {% endfor %}
      </table>
      
      <a href = "/">Go back to home page</a>
   </body>
</html>

最後,‘/’ URL規則呈現一個‘home.html’,作為應用程式的入口點。

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

以下是Flask-SQLite應用程式的完整程式碼。

from flask import Flask, render_template, request
import sqlite3 as sql
app = Flask(__name__)

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

@app.route('/enternew')
def new_student():
   return render_template('student.html')

@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
   if request.method == 'POST':
      try:
         nm = request.form['nm']
         addr = request.form['add']
         city = request.form['city']
         pin = request.form['pin']
         
         with sql.connect("database.db") as con:
            cur = con.cursor()
            
            cur.execute("INSERT INTO students (name,addr,city,pin) 
               VALUES (?,?,?,?)",(nm,addr,city,pin) )
            
            con.commit()
            msg = "Record successfully added"
      except:
         con.rollback()
         msg = "error in insert operation"
      
      finally:
         return render_template("result.html",msg = msg)
         con.close()

@app.route('/list')
def list():
   con = sql.connect("database.db")
   con.row_factory = sql.Row
   
   cur = con.cursor()
   cur.execute("select * from students")
   
   rows = cur.fetchall();
   return render_template("list.html",rows = rows)

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

從Python shell執行此指令碼,並啟動開發伺服器。在瀏覽器中訪問https://:5000/,它將顯示如下所示的簡單選單:

Simple Menu

單擊‘新增新記錄’連結以開啟學生資訊表單。

Adding New Record

填寫表單欄位並提交。底層函式將記錄插入學生表中。

Record Successfully Added

返回主頁並單擊‘顯示列表’連結。將顯示顯示示例資料的表格。

Table Showing Sample Data

Flask – SQLAlchemy

在Flask Web應用程式中使用原始SQL對資料庫執行CRUD操作可能很繁瑣。相反,SQLAlchemy是一個Python工具包,是一個強大的OR Mapper,它為應用程式開發人員提供了SQL的全部功能和靈活性。Flask-SQLAlchemy是Flask擴充套件,它為您的Flask應用程式添加了對SQLAlchemy的支援。

什麼是ORM(物件關係對映)?

大多數程式語言平臺都是面向物件的。另一方面,RDBMS伺服器中的資料儲存為表。物件關係對映是一種將物件引數對映到底層RDBMS表結構的技術。ORM API提供執行CRUD操作的方法,而無需編寫原始SQL語句。

在本節中,我們將研究Flask-SQLAlchemy的ORM技術並構建一個小型Web應用程式。

步驟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操作的輔助函式。它還提供一個父模型類,使用者定義的模型就是使用它宣告的。在下面的程式碼片段中,建立了一個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()

SQLAlchemySession物件管理ORM物件的所有永續性操作。

以下會話方法執行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">City</label><br>
         <input type = "text" name = "pin" placeholder = "pin" /><br>
         <input type = "submit" value = "Submit" />
      </form>
   </body>
</html>

當http方法檢測為POST時,表單資料將新增到students表中,並且應用程式將返回主頁並顯示已新增的資料。

@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)

從Python shell執行指令碼,並在瀏覽器中輸入https://:5000/

Flask SQLAlchemy Example

單擊‘新增學生’連結以開啟學生資訊表單。

Add Student

填寫表單並提交。主頁將重新出現,其中包含提交的資料。

我們可以看到如下所示的輸出。

Flask SQLAlchemy Example Output

Flask – Sijax

Sijax代表‘Simple Ajax’,它是一個Python/jQuery庫,旨在幫助您輕鬆地將Ajax引入您的應用程式。它使用jQuery.ajax發出AJAX請求。

安裝

Flask-Sijax的安裝很簡單。

pip install flask-sijax

配置

  • SIJAX_STATIC_PATH - 您希望映象Sijax javascript檔案的靜態路徑。預設位置是static/js/sijax。在這個資料夾中,儲存了sijax.jsjson2.js檔案。

  • SIJAX_JSON_URI - 載入json2.js靜態檔案的URI

Sijax使用JSON在瀏覽器和伺服器之間傳遞資料。這意味著瀏覽器要麼需要原生支援JSON,要麼從json2.js檔案獲得JSON支援。

以這種方式註冊的函式無法提供Sijax功能,因為預設情況下無法使用POST方法訪問它們(而Sijax使用POST請求)。

要使檢視函式能夠處理Sijax請求,請使用@app.route('/url', methods = ['GET', 'POST'])使其可以透過POST訪問,或者使用@flask_sijax.route輔助裝飾器,如下所示:

@flask_sijax.route(app, '/hello')

每個Sijax處理程式函式(像這個一樣)至少自動接收一個引數,就像Python將'self'傳遞給物件方法一樣。'obj_response'引數是函式與瀏覽器對話的方式。

def say_hi(obj_response):
   obj_response.alert('Hi there!')

當檢測到Sijax請求時,Sijax會像這樣處理它:

g.sijax.register_callback('say_hi', say_hi)
   return g.sijax.process_request()

Sijax應用程式

一個最小的Sijax應用程式程式碼如下所示:

import os
from flask import Flask, g
from flask_sijax import sijax

path = os.path.join('.', os.path.dirname(__file__), 'static/js/sijax/')
app = Flask(__name__)

app.config['SIJAX_STATIC_PATH'] = path
app.config['SIJAX_JSON_URI'] = '/static/js/sijax/json2.js'
flask_sijax.Sijax(app)

@app.route('/')
def index():
   return 'Index'
	
@flask_sijax.route(app, '/hello')
def hello():
   def say_hi(obj_response):
      obj_response.alert('Hi there!')
   if g.sijax.is_sijax_request:
      # Sijax request detected - let Sijax handle it
      g.sijax.register_callback('say_hi', say_hi)
      return g.sijax.process_request()
      return _render_template('sijaxexample.html')

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

當向伺服器發出Sijax請求(一個特殊的jQuery.ajax()請求)時,伺服器會透過g.sijax.is_sijax_request()檢測到此請求,在這種情況下,您可以讓Sijax處理請求。

所有使用g.sijax.register_callback()註冊的函式都可供瀏覽器呼叫。

呼叫g.sijax.process_request()告訴Sijax執行適當的(先前註冊的)函式並將響應返回給瀏覽器。

Flask – 部署

外部可見伺服器

開發伺服器上的Flask應用程式只能在設定了開發環境的計算機上訪問。這是預設行為,因為在除錯模式下,使用者可以在計算機上執行任意程式碼。

如果停用了debug,可以透過將主機名設定為‘0.0.0.0’來使本地計算機上的開發伺服器可供網路上的使用者使用。

app.run(host = ’0.0.0.0’)

因此,您的作業系統將監聽所有公共IP。

部署

要從開發環境切換到成熟的生產環境,需要將應用程式部署到真實的Web伺服器上。根據您的情況,可以使用不同的選項來部署Flask Web應用程式。

對於小型應用程式,您可以考慮將其部署在以下任何託管平臺上,所有這些平臺都為小型應用程式提供免費計劃。

  • Heroku
  • dotcloud
  • webfaction

Flask應用程式可以部署在這些雲平臺上。此外,還可以將Flask應用程式部署到Google雲平臺。Localtunnel服務允許您共享localhost上的應用程式,而無需更改DNS和防火牆設定。

如果您傾向於使用專用Web伺服器來代替上述共享平臺,則可以使用以下選項。

mod_wsgi

mod_wsgi是一個Apache模組,它提供了一個符合WSGI的介面,用於在Apache伺服器上託管基於Python的Web應用程式。

安裝mod_wsgi

要直接從PyPi安裝官方版本,您可以執行:

pip install mod_wsgi

要驗證安裝是否成功,請使用start-server命令執行mod_wsgi-express指令碼:

mod_wsgi-express start-server

這將在埠8000上啟動Apache/mod_wsgi。然後,您可以透過將瀏覽器指向以下地址來驗證安裝是否成功:

https://:8000/

建立.wsgi檔案

應該有一個yourapplication.wsgi檔案。此檔案包含mod_wsgi程式碼,該程式碼在啟動時執行以獲取應用程式物件。對於大多數應用程式,以下檔案應該足夠了:

from yourapplication import app as application

確保yourapplication和所有正在使用的庫都在python載入路徑上。

配置Apache

您需要告訴mod_wsgi您的應用程式的位置。

<VirtualHost *>
   ServerName example.com
   WSGIScriptAlias / C:\yourdir\yourapp.wsgi

   <Directory C:\yourdir>
      Order deny,allow
      Allow from all
   </Directory>

</VirtualHost>

獨立WSGI容器

有很多流行的用Python編寫的伺服器包含WSGI應用程式並提供HTTP服務。

  • Gunicorn
  • Tornado
  • Gevent
  • Twisted Web

Flask – FastCGI

FastCGI是將Flask應用程式部署到nginx、lighttpd和Cherokee等Web伺服器上的另一個選項。

配置FastCGI

首先,您需要建立FastCGI伺服器檔案。讓我們稱之為yourapplication.fcgi

from flup.server.fcgi import WSGIServer
from yourapplication import app

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

nginx和舊版本的lighttpd需要明確傳遞套接字才能與FastCGI伺服器通訊。為此,您需要將套接字的路徑傳遞給WSGIServer

WSGIServer(application, bindAddress = '/path/to/fcgi.sock').run()

配置Apache

對於基本的Apache部署,您的.fcgi檔案將出現在您的應用程式URL中,例如example.com/yourapplication.fcgi/hello/。有幾種方法可以配置您的應用程式,以便yourapplication.fcgi不會出現在URL中。

<VirtualHost *>
   ServerName example.com
   ScriptAlias / /path/to/yourapplication.fcgi/
</VirtualHost>

配置lighttpd

lighttpd的基本配置如下所示:

fastcgi.server = ("/yourapplication.fcgi" => ((
   "socket" => "/tmp/yourapplication-fcgi.sock",
   "bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
   "check-local" => "disable",
   "max-procs" => 1
)))

alias.url = (
   "/static/" => "/path/to/your/static"
)

url.rewrite-once = (
   "^(/static($|/.*))$" => "$1",
   "^(/.*)$" => "/yourapplication.fcgi$1"
)

請記住啟用FastCGI、別名和重寫模組。此配置將應用程式繫結到/yourapplication

廣告