Web應(yīng)用程序框架或簡單的Web框架表示一組庫和模塊,使Web應(yīng)用程序開發(fā)人員能夠編寫應(yīng)用程序,而不必擔心協(xié)議,線程管理等低級細節(jié)。
Flask是一個用Python編寫的Web應(yīng)用程序框架。它由Armin Ronacher開發(fā),他領(lǐng)導(dǎo)一個名為Pocco的國際Python愛好者團體。Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。兩者都是Pocco項目。
Web服務(wù)器網(wǎng)關(guān)接口(WSGI)已被用作Python Web應(yīng)用程序開發(fā)的標準。WSGI是Web服務(wù)器和Web應(yīng)用程序之間通用接口的規(guī)范。
它是一個WSGI工具包,它實現(xiàn)了請求,響應(yīng)對象和其他實用函數(shù)。這使得能夠在其上構(gòu)建Web框架。Flask框架使用Werkzeug作為其基礎(chǔ)之一。
Jinja2是Python的一個流行的模板引擎。Web模板系統(tǒng)將模板與特定數(shù)據(jù)源組合以呈現(xiàn)動態(tài)網(wǎng)頁。
Flask通常被稱為微框架。它旨在保持應(yīng)用程序的核心簡單而可擴展。Flask沒有用于數(shù)據(jù)庫處理的內(nèi)置抽象層,也沒有形成驗證支持。相反,F(xiàn)lask支持擴展以向應(yīng)用程序添加此類功能。一些流行的Flask擴展將在本教程后面討論。
安裝Flask通常需要Python 2.6或更高版本。雖然Flask及其依賴項適用于Python 3(Python 3.3以后版本),但是許多Flask擴展不能正確支持它。因此,建議在Python 2.7上安裝Flask。
virtualenv是一個虛擬的Python環(huán)境構(gòu)建器。它幫助用戶并行創(chuàng)建多個Python環(huán)境。因此,它可以避免不同版本的庫之間的兼容性問題。
以下命令用于安裝virtualenv:
pip install virtualenv
此命令需要管理員權(quán)限。您可以在Linux / Mac OS上的 pip 之前添加 sudo 。如果您使用的是Windows,請以管理員身份登錄。在Ubuntu上, virtualenv可以使用它的包管理器安裝。
Sudo apt-get install virtualenv
安裝后,將在文件夾中創(chuàng)建新的虛擬環(huán)境。
mkdir newproj cd newproj virtualenv venv
要在 Linux / OS X 上激活相應(yīng)的環(huán)境,請使用以下命令:
venv/bin/activate
要在 Windows 上激活相應(yīng)的環(huán)境,可以使用以下命令:
venv\scripts\activate
我們現(xiàn)在準備在這個環(huán)境中安裝Flask:
pip install Flask
上述命令可以直接運行,不需要系統(tǒng)范圍安裝的虛擬環(huán)境。
為了測試 Flask 安裝,請在編輯器中將以下代碼輸入 Hello.py:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World’ if __name__ == '__main__': app.run()
必須在項目中導(dǎo)入Flask模塊。Flask類的一個對象是我們的WSGI應(yīng)用程序。
Flask構(gòu)造函數(shù)使用當前模塊(__name __)的名稱作為參數(shù)。
Flask類的route()函數(shù)是一個裝飾器,它告訴應(yīng)用程序哪個URL應(yīng)該調(diào)用相關(guān)的函數(shù)。
app.route(rule, options)
rule 參數(shù)表示與該函數(shù)的URL綁定。
options 是要轉(zhuǎn)發(fā)給基礎(chǔ)Rule對象的參數(shù)列表。
在上面的示例中,'/ ' URL與hello_world()函數(shù)綁定。因此,當在瀏覽器中打開web服務(wù)器的主頁時,將呈現(xiàn)該函數(shù)的輸出。
最后,F(xiàn)lask類的run()方法在本地開發(fā)服務(wù)器上運行應(yīng)用程序。
app.run(host, port, debug, options)
所有參數(shù)都是可選的
序號 | 參數(shù)與描述 |
---|---|
1 | host 要監(jiān)聽的主機名。 默認為127.0.0.1(localhost)。設(shè)置為“0.0.0.0”以使服務(wù)器在外部可用 |
2 | port 默認值為5000 |
3 | debug 默認為false。 如果設(shè)置為true,則提供調(diào)試信息 |
4 | options 要轉(zhuǎn)發(fā)到底層的Werkzeug服務(wù)器。 |
上面給出的Python腳本是從Python shell執(zhí)行的。
Python Hello.py
Python shell中的消息通知您:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
在瀏覽器中打開上述URL(localhost:5000)。將顯示“Hello World”消息。
通過調(diào)用run()方法啟動Flask應(yīng)用程序。但是,當應(yīng)用程序正在開發(fā)中時,應(yīng)該為代碼中的每個更改手動重新啟動它。為避免這種不便,請啟用調(diào)試支持。如果代碼更改,服務(wù)器將自行重新加載。它還將提供一個有用的調(diào)試器來跟蹤應(yīng)用程序中的錯誤(如果有的話)。
在運行或?qū)⒄{(diào)試參數(shù)傳遞給run()方法之前,通過將application對象的debug屬性設(shè)置為True來啟用Debug模式。
app.debug = True app.run() app.run(debug = True)
現(xiàn)代Web框架使用路由技術(shù)來幫助用戶記住應(yīng)用程序URL。 可以直接訪問所需的頁面,而無需從主頁導(dǎo)航。
Flask中的 route()裝飾器用于將URL綁定到函數(shù)。 例如 -
@app.route(‘/hello’) def hello_world(): return ‘hello world’
這里,URL \'/ hello\'規(guī)則綁定到 hello_world()函數(shù)。 因此,如果用戶訪問 http:// localhost:5000 / hello URL, hello_world()函數(shù)的輸出將在瀏覽器中呈現(xiàn)。
應(yīng)用程序?qū)ο蟮?strong> add_url_rule()函數(shù)也可用于使用函數(shù)綁定URL,如上例所示,使用 route()。
裝飾者的目的也由以下表示 -
def hello_world(): return ‘hello world’ app.add_url_rule(‘/’, ‘hello’, hello_world)
可以通過向規(guī)則參數(shù)添加可變部分來動態(tài)構(gòu)建URL。 此可變部分標記為< variable-name> 。 它作為關(guān)鍵字參數(shù)傳遞到與規(guī)則相關(guān)聯(lián)的函數(shù)。
在以下示例中, route()裝飾器的規(guī)則參數(shù)包含附加到URL \'/ hello\'的< name> 因此,如果在瀏覽器中輸入 http:// localhost:5000 / hello / TutorialsPoint 作為 URL ,則\'TutorialPoint\' 提供給 hello()函數(shù)作為參數(shù)。
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運行它。 接下來,打開瀏覽器并輸入URL http:// localhost:5000 / hello / TutorialsPoint。
以下輸出將在瀏覽器中顯示。
Hello TutorialsPoint!
除了默認字符串變量部分之外,還可以使用以下轉(zhuǎn)換器構(gòu)建規(guī)則:
Sr.No | 轉(zhuǎn)換器 描述 |
---|---|
1 | int 接受整數(shù) |
2 | float 浮點值 |
3 | 路徑 接受用作目錄分隔符的斜杠 |
在下面的代碼中,使用所有這些構(gòu)造函數(shù)。
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運行上面的代碼。 訪問瀏覽器中的網(wǎng)址 http:// localhost:5000 / blog / 11 。
給定的數(shù)字用作 show_blog()函數(shù)的參數(shù)。 瀏覽器顯示以下輸出 -
Blog Number 11
在瀏覽器中輸入此網(wǎng)址 - http:// localhost:5000 / rev / 1.1
revision()函數(shù)將浮點數(shù)作為參數(shù)。 以下結(jié)果顯示在瀏覽器窗口中 -
Revision Number 1.100000
Flask的URL規(guī)則基于 Werkzeug的路由模塊。 這確保形成的URL是唯一的,并基于Apache規(guī)定的先例。
考慮以下腳本中定義的規(guī)則 -
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()
這兩個規(guī)則看起來類似,但在第二個規(guī)則中,使用尾部斜杠(/)。 因此,它成為一個規(guī)范的URL。 因此,使用 / python 或 / python / 返回相同的輸出。 但是,如果是第一個規(guī)則, / flask / 網(wǎng)址會產(chǎn)生 404未找到 頁。
url_for()函數(shù)對于動態(tài)構(gòu)建特定函數(shù)的URL非常有用。 該函數(shù)接受函數(shù)的名稱作為第一個參數(shù),以及一個或多個關(guān)鍵字參數(shù),每個參數(shù)對應(yīng)于URL的可變部分。
以下腳本演示了如何使用 url_for()函數(shù)。
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)
上述腳本有一個函數(shù) user(name),它接受來自URL的參數(shù)的值。
User()函數(shù)檢查接收的參數(shù)是否與\'admin\'匹配。 如果匹配,則使用 url_for()將應(yīng)用程序重定向到 hello_admin()函數(shù),否則將 hello_guest 參數(shù)作為guest參數(shù)。
保存上面的代碼并從Python shell運行。
打開瀏覽器并輸入網(wǎng)址為 - http:// localhost:5000 / hello / admin
在瀏覽器中的應(yīng)用程序響應(yīng)是 -
Hello Admin
在瀏覽器中輸入以下網(wǎng)址 - http:// localhost:5000 / hello / mvl
應(yīng)用程序響應(yīng)現(xiàn)在更改為 -
Hello mvl as Guest
Http協(xié)議是萬維網(wǎng)中數(shù)據(jù)通信的基礎(chǔ)。 在此協(xié)議中定義了從指定的URL檢索不同的數(shù)據(jù)方法。
下表總結(jié)了不同的http方法 -
Sr.No | 方法&amp; 描述 |
---|---|
1 | GET 以未加密的形式將數(shù)據(jù)發(fā)送到服務(wù)器。 最常用的方法。 |
2 | HEAD 和GET一樣,但沒有響應(yīng)體 |
3 | POST 用于將HTML表單數(shù)據(jù)發(fā)送到服務(wù)器。 POST方法接收的數(shù)據(jù)不由服務(wù)器緩存。 |
4 | PUT 用所上傳的內(nèi)容替換目標資源的所有當前表示。 |
5 | 刪除 刪除由URL給定的目標資源的所有當前表示 |
默認情況下,F(xiàn)lask路由響應(yīng) GET 請求。 但是,可以通過為 route()裝飾器提供方法參數(shù)來更改此偏好。
為了演示在URL路由中使用 POST 方法,首先讓我們創(chuàng)建一個HTML表單,并使用 POST 方法將表單數(shù)據(jù)發(fā)送到URL。
將以下腳本另存為login.html
<html> <body> <form action = "http://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>
現(xiàn)在在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)
開發(fā)服務(wù)器開始運行后,在瀏覽器中打開 login.html ,在文本字段中輸入name,然后單擊提交。
表單數(shù)據(jù)被發(fā)送到表單標簽的action子句中的URL。
http:// localhost / login 映射到 login()函數(shù)。 由于服務(wù)器通過 POST 方法接收數(shù)據(jù),從表單數(shù)據(jù)獲得的“nm”參數(shù)的值通過 -
user = request.form['nm']
它作為可變部分傳遞給\'/ success\' URL。 瀏覽器在窗口中顯示歡迎消息。
將 login.html 中的方法參數(shù)更改為\'GET\',然后在瀏覽器中再次打開。 在服務(wù)器上接收的數(shù)據(jù)是通過 GET 方法。 \'nm\'參數(shù)的值現(xiàn)在通過 -
User = request.args.get(‘nm’)
這里, args 是包含表單參數(shù)及其對應(yīng)值對的列表的字典對象。 與\'nm\'參數(shù)對應(yīng)的值將像之前一樣傳遞到\'/ success\'URL。
可以以HTML的形式返回綁定到某個URL的函數(shù)的輸出。 例如,在以下腳本中, hello()函數(shù)將使用&lt; h1&gt; 標簽呈現(xiàn)\'Hello World\'
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內(nèi)容很麻煩,尤其是當需要放置可變數(shù)據(jù)和Python語言元素(如條件語句或循環(huán))時。 這需要經(jīng)常從HTML轉(zhuǎn)義。
這是可以利用基于Flask的 Jinja2 模板引擎的地方。 代替從函數(shù)返回硬編碼HTML,可以通過 render_template()函數(shù)呈現(xiàn)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將嘗試在templates文件夾中找到與此腳本所在的文件夾中的HTML文件。
術(shù)語\'web模板系統(tǒng)\'是指設(shè)計一個HTML腳本,其中可以動態(tài)插入變量數(shù)據(jù)。 web模板系統(tǒng)包括模板引擎,某種數(shù)據(jù)源和模板處理器。
Flask使用 jinja2 模板引擎。 Web模板包含用于變量和表達式(在這些情況下為Python表達式)的HTML語法分散的占位符,在呈現(xiàn)模板時,這些占位符是替換的值。
以下代碼在模板文件夾中另存為 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)
當開發(fā)服務(wù)器開始運行時,打開瀏覽器并輸入URL - http:// localhost:5000 / hello / mvl
網(wǎng)址的變量部分插入到 {{name}} 占位符。
jinja2 模板引擎使用以下定界符從HTML轉(zhuǎn)義。
在下面的示例中,演示了在模板中使用條件語句。 到 hello()函數(shù)的URL規(guī)則接受整數(shù)參數(shù)。 它被傳遞到 hello.html 模板。 在其內(nèi)部,比較接收的數(shù)字(標記)的值(大于或小于50),并且相應(yīng)地有條件地呈現(xiàn)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-else 和 endif 由分隔符 {%..%} 括起。
運行Python腳本并訪問網(wǎng)址 http:// localhost / hello / 60 ,然后訪問 http:// localhost / hello / 30 ,查看有條件地更改HTML的輸出。
Python循環(huán)結(jié)構(gòu)也可以在模板中使用。 在以下腳本中,當網(wǎng)址 http:// localhost:5000 / result 時, result()函數(shù)會將字典對象發(fā)送到模板 results.html >在瀏覽器中打開。
result.html 的模板部分使用 for循環(huán)來呈現(xiàn)字典對象 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腳本作為 result.html 保存在templates文件夾中。
<!doctype html> <html> <body> <table border = 1> {% for key, value in result.iteritems() %} <tr> <th> {{ key }} </th> <td> {{ value }} </td> </tr> {% endfor %} </table> </body> </html>
這里,對應(yīng)于 For 循環(huán)的Python語句也包含在{%..%}中,而表達式鍵和值 } 。
開發(fā)開始后,在瀏覽器中打開 http:// localhost:5000 / result 即可獲得以下輸出。
網(wǎng)絡(luò)應(yīng)用程序通常需要一個靜態(tài)文件,例如支持顯示網(wǎng)頁的 javascript 文件或 CSS 文件。 通常,網(wǎng)絡(luò)服務(wù)器配置為為您提供服務(wù),但在開發(fā)過程中,這些文件是從您的軟件包中的 static 文件夾或模塊旁邊提供的,并且可以從 i> / static 。
特殊的端點\'static\'用于為靜態(tài)文件生成URL。
在下面的示例中, index.html 中的 OnClick HTML事件按鈕調(diào)用 hello.js 中定義的 / b>,它顯示在Flask應(yīng)用程序的\'/\' 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()函數(shù)。
function sayHello() { alert("Hello World") }
來自客戶端網(wǎng)頁的數(shù)據(jù)作為全局請求對象發(fā)送到服務(wù)器。 為了處理請求數(shù)據(jù),它應(yīng)該從Flask模塊導(dǎo)入。
請求對象的重要屬性如下所列 -
表單 - 它是一個字典對象,包含表單參數(shù)的鍵和值對及其值。
args - 在問號(?)后面的URL的一部分的查詢字符串的解析內(nèi)容。
Cookie - 保存Cookie名稱和值的字典對象。
文件 - 與上傳的文件有關(guān)的數(shù)據(jù)。
方法 - 當前請求方法。
我們已經(jīng)看到,可以在URL規(guī)則中指定http方法。 觸發(fā)函數(shù)接收的 Form 數(shù)據(jù)可以以字典對象的形式收集它并將其轉(zhuǎn)發(fā)到模板以在相應(yīng)的網(wǎng)頁上呈現(xiàn)它。
在以下示例中,\'/\'網(wǎng)址會呈現(xiàn)具有表單的網(wǎng)頁(student.html)。 填入的數(shù)據(jù)會發(fā)布到觸發(fā) result()函數(shù)的\'/ result\'網(wǎng)址。
results()函數(shù)收集呈現(xiàn)在 request.form 中的表單數(shù)據(jù),并將其發(fā)送給 result.html 。
模板動態(tài)呈現(xiàn)形式數(shù)據(jù)的HTML表格。
下面給出的是應(yīng)用程序的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 = "http://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> <html> <body> <table border = 1> {% for key, value in result.iteritems() %} <tr> <th> {{ key }} </th> <td> {{ value }} </td> </tr> {% endfor %} </table> </body> </html>
運行Python腳本,并在瀏覽器中輸入網(wǎng)址 http:// localhost:5000 / 。
當點擊提交按鈕時,表單數(shù)據(jù)以HTML表格的形式呈現(xiàn)在 result.html 上。
Cookie以文本文件的形式存儲在客戶端的計算機上。 其目的是記住和跟蹤與客戶的使用相關(guān)的數(shù)據(jù),以獲得更好的訪問者體驗和網(wǎng)站統(tǒng)計信息。
請求對象包含Cookie的屬性。 它是所有cookie變量及其對應(yīng)值的字典對象,客戶端已傳輸。 除此之外,cookie還存儲其到期時間,路徑和站點的域名。
在Flask中,對響應(yīng)對象設(shè)置cookie。 使用 make_response()函數(shù)從視圖函數(shù)的返回值獲取響應(yīng)對象。 之后,使用響應(yīng)對象的 set_cookie()函數(shù)來存儲cookie。
讀回cookie很容易。 request.cookies 屬性的 get()方法用于讀取cookie。
在以下Flask應(yīng)用程序中,當您訪問\'/\' 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>
表單發(fā)布到\'/ setcookie\' URL。 相關(guān)聯(lián)的視圖函數(shù)設(shè)置Cookie名稱 userID 并呈現(xiàn)另一個頁面。
@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\'包含指向另一個視圖函數(shù) getcookie()的超鏈接,它讀回并在瀏覽器中顯示Cookie值。
@app.route('/getcookie') def getcookie(): name = request.cookies.get('userID') return '<h1>welcome '+name+'</h1>'
運行應(yīng)用程序,并訪問 http:// localhost:5000 /
設(shè)置cookie的結(jié)果顯示為這樣 -
回讀cookie的輸出如下所示。
與Cookie不同,會話數(shù)據(jù)存儲在服務(wù)器上。 會話是客戶端登錄到服務(wù)器并注銷它的時間間隔。 需要在該會話中保存的數(shù)據(jù)存儲在服務(wù)器上的臨時目錄中。
與每個客戶端的會話都分配有會話ID 。 會話數(shù)據(jù)存儲在cookie的頂部,服務(wù)器對它們進行加密簽名。 對于此加密,F(xiàn)lask應(yīng)用程序需要定義 SECRET_KEY 。
Session對象也是一個字典對象,包含會話變量和關(guān)聯(lián)值的鍵值對。
例如,要設(shè)置一個\'username\'會話變量,請使用語句 -
Session[‘username’] = ’admin’
要釋放會話變量,請使用 pop()方法。
session.pop('username', None)
以下代碼是Flask中的會話工作的簡單演示。 URL \'/\'只是提示用戶登錄,因為未設(shè)置會話變量\'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()視圖函數(shù)時,因為它是通過GET方法調(diào)用的,打開一個登錄表單。
表單發(fā)布回\'/ login\',現(xiàn)在設(shè)置會話變量。 應(yīng)用程序重定向到\'/\'。 此時會找到會話變量\'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> '''
應(yīng)用程序還包含一個 logout()視圖函數(shù),它會彈出\'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'))
運行應(yīng)用程序并訪問主頁。 (確保設(shè)置應(yīng)用程序的 secret_key )
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) app.secret_key = 'any random string’
輸出將顯示如下所示。 點擊鏈接“點擊此處登錄”。
鏈接將被定向到另一個屏幕。 鍵入“admin”。
屏幕將顯示消息“以管理員身份登錄”。
Flask類有一個 redirect()函數(shù)。 調(diào)用時,它返回一個響應(yīng)對象,并將用戶重定向到具有指定狀態(tài)代碼的另一個目標位置。
redirect()函數(shù)的原型如下 -
Flask.redirect(location, statuscode, response)
在上述函數(shù)中 -
location 參數(shù)是應(yīng)重定向響應(yīng)的網(wǎng)址。
statuscode 發(fā)送到瀏覽器標頭,默認為302。
response 參數(shù)用于實例化響應(yīng)。
以下狀態(tài)代碼已標準化 -
默認狀態(tài)代碼為 302 ,用于\'found\'。
在以下示例中, redirect()函數(shù)用于在登錄嘗試失敗時再次顯示登錄頁面。
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)
Flask類具有帶錯誤代碼的 abort()函數(shù)。
Flask.abort(code)
代碼參數(shù)采用以下值之一:
400 - 用于錯誤請求
401 - 用于未經(jīng)身份驗證
403 - Forbidden
404 - 找不到
406 - 表示不接受
415 - 用于不支持的媒體類型
429 - 請求過多
讓我們在上述代碼中的 login()函數(shù)中稍作更改。 如果要顯示\'Unauthurized\'頁面,而不是重新顯示登錄頁面,請?zhí)鎿Q為調(diào)用 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)
好的基于GUI的應(yīng)用程序向用戶提供關(guān)于交互的反饋。 例如,桌面應(yīng)用程序使用對話框或消息框,JavaScript使用警報用于類似目的。
在Flask Web應(yīng)用程序中生成這樣的信息性消息很容易。 Flask框架的閃爍系統(tǒng)使得可以在一個視圖中創(chuàng)建消息,并在稱為下一的視圖函數(shù)中呈現(xiàn)它。
Flask模塊包含 flash()方法。 它將消息傳遞給下一個請求,通常是一個模板。
flash(message, category)
這里,
message 參數(shù)是要閃爍的實際消息。
category 參數(shù)是可選的。 它可以是“錯誤”,“信息”或“警告”。
為了從會話中刪除郵件,模板調(diào)用 get_flashed_messages()。
get_flashed_messages(with_categories, category_filter)
兩個參數(shù)都是可選的。 如果接收到的消息具有類別,則第一個參數(shù)是元組。 第二個參數(shù)僅用于顯示特定消息。
以下閃爍模板中接收的消息。
{% 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')
該鏈接會將用戶引導(dǎo)到顯示登錄表單的\'/ login\' URL。 提交時, login()視圖函數(shù)驗證用戶名和密碼,并相應(yīng)閃爍\'success\'消息或創(chuàng)建\'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)
如果出現(xiàn)錯誤,則會重新顯示登錄模板,并顯示錯誤消息。
<!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>
另一方面,如果 login 成功,則索引模板上會顯示成功消息。
<!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消息閃爍示例的完整代碼 -
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)
執(zhí)行上述代碼后,您將看到如下所示的屏幕。
當您點擊鏈接,您將被定向到登錄頁面。
輸入用戶名和密碼。
點擊登錄。 將顯示一條消息“您已成功登錄”。
在Flask中處理文件上傳非常容易。 它需要一個HTML表單,其enctype屬性設(shè)置為“multipart / form-data”,將文件發(fā)布到URL。 URL處理程序從 request.files [] 對象中提取文件,并將其保存到所需的位置。
每個上傳的文件首先保存在服務(wù)器上的臨時位置,然后實際保存到其最終位置。 目標文件的名稱可以是硬編碼的,也可以從 request.files [file] 對象的filename屬性中獲取。 但是,建議使用 secure_filename()函數(shù)獲取安全版本。
可以在Flask對象的配置設(shè)置中定義默認上傳文件夾的路徑和上傳文件的最大大小。
app.config[‘UPLOAD_FOLDER’] | 定義上傳文件夾的路徑 |
app.config[‘MAX_CONTENT_PATH’] | 指定要上傳的文件的最大大小(以字節(jié)為單位) |
以下代碼具有在模板文件夾中顯示\'upload.html\'的\'/ upload\'網(wǎng)址規(guī)則,以及\'/ upload-file\' 調(diào)用 uploader()函數(shù)處理上傳過程的網(wǎng)址規(guī)則。
\'upload.html\'有一個文件選擇器按鈕和一個提交按鈕。
<html> <body> <form action = "http://localhost:5000/uploader" method = "POST" enctype = "multipart/form-data"> <input type = "file" name = "file" /> <input type = "submit"/> </form> </body> </html>
您將看到如下所示的屏幕。
選擇文件后,單擊提交。 表單的后方法調(diào)用\'/ upload_file\'網(wǎng)址。 底層函數(shù) uploader()執(zhí)行保存操作。
以下是Flask應(yīng)用程序的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通常被稱為微框架,因為核心功能包括基于 Werkzeug 的WSGI和路由以及基于 Jinja2 的模板引擎。 此外,F(xiàn)lask框架還支持cookie和會話,以及像 JSON ,靜態(tài)文件等Web幫助。顯然,這不足以開發(fā)一個成熟的Web應(yīng)用程序。 這是Flask擴展在哪里。 Flask擴展為Flask框架提供了可擴展性。
有大量的Flask擴展可用。 Flask擴展是一個Python模塊,它向Flask應(yīng)用程序添加特定類型的支持。 Flask擴展注冊表是可用的擴展的目錄。 所需的擴展程序可以通過 pip 實用程序下載。
在本教程中,我們將討論以下重要的Flask擴展 -
Flask Mail - 為Flask應(yīng)用程序提供SMTP接口
Flask WTF - 添加了WTForms的渲染和驗證
Flask SQLAlchemy - 為Flask應(yīng)用程序添加SQLAlchemy支持
Flask Sijax - Sijax的接口 - Python / jQuery庫,使AJAX易于在Web應(yīng)用程序中使用
每種類型的擴展通常提供有關(guān)其使用的廣泛文檔。 由于擴展是一個Python模塊,它需要導(dǎo)入才能使用。 瓶子延伸部分通常命名為flask-foo。 要導(dǎo)入,
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
基于web的應(yīng)用程序通常需要具有向用戶/客戶端發(fā)送郵件的功能。 Flask-Mail 擴展功能可以很容易地與任何電子郵件服務(wù)器建立簡單的界面。
首先,F(xiàn)lask-Mail擴展應(yīng)該在pip實用程序的幫助下安裝。
pip install Flask-Mail
然后Flask-Mail需要通過設(shè)置以下應(yīng)用程序參數(shù)的值進行配置。
Sr.No | 參數(shù)&amp; 描述 |
---|---|
1 | MAIL_SERVER 電子郵件服務(wù)器的名稱/ IP地址 |
2 | MAIL_PORT 使用的服務(wù)器的端口號 |
3 | MAIL_USE_TLS 啟用/禁用傳輸安全層加密 |
4 | MAIL_USE_SSL 啟用/禁用安全套接字層加密 |
5 | MAIL_DEBUG 調(diào)試支持。 默認是Flask應(yīng)用程序的調(diào)試狀態(tài) |
6 | MAIL_USERNAME 發(fā)件人的用戶名 |
7 | MAIL_PASSWORD 發(fā)件人的密碼 |
8 | MAIL_DEFAULT_SENDER 設(shè)置默認發(fā)件人 |
9 | MAIL_MAX_EMAILS 設(shè)置要發(fā)送的最大電子郵件 |
10 | MAIL_SUPPRESS_SEND 如果app.testing設(shè)置為true,則發(fā)送抑制 |
11 | MAIL_ASCII_ATTACHMENTS 如果設(shè)置為true,則附加的文件名轉(zhuǎn)換為ASCII |
flask-mail模塊包含以下重要類的定義。
它管理電子郵件消息傳遞需求。 類構(gòu)造函數(shù)采用以下形式 -
flask-mail.Mail(app = None)
構(gòu)造函數(shù)將Flask應(yīng)用程序?qū)ο笞鳛閰?shù)。
Sr.No | 方法&amp; 描述 |
---|---|
1 | send() 發(fā)送消息類對象的內(nèi)容 |
2 | connect() 打開與郵件主機的連接 |
3 | send_message() 發(fā)送消息對象 |
它封裝了一封電子郵件。 消息類構(gòu)造函數(shù)有幾個參數(shù) -
flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, reply-to, date, charset, extra_headers, mail_options, rcpt_options)
attach() - 在郵件中添加附件。 此方法采用以下參數(shù) -
filename - 要附加的文件的名稱
content_type - MIME類型的文件
data - 原始文件數(shù)據(jù)
處置 - 內(nèi)容處置(如果有)。
add_recipient() - 向郵件中添加另一個收件人
在下面的示例中,Google gmail服務(wù)的SMTP服務(wù)器用作Flask-Mail配置的MAIL_SERVER。
步驟1 - 從代碼中的郵箱模塊導(dǎo)入郵件和郵件類。
from flask_mail import Mail, Message
步驟2 - 然后按照以下設(shè)置配置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 - 創(chuàng)建Mail類的實例。
mail = Mail(app)
步驟4 - 在由URL規(guī)則(\'/\')映射的Python函數(shù)中設(shè)置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中運行以下腳本并訪問 http:// localhost: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服務(wù)中的內(nèi)置安全功能可能會阻止此次登錄嘗試。 您可能需要降低安全級別。 請登錄您的Gmail帳戶,然后訪問此鏈接,以減少 安全。
Web應(yīng)用程序的一個重要方面是為用戶提供一個用戶界面。 HTML提供了一個&lt; form&gt; 標簽,用于設(shè)計接口。 可以適當?shù)厥褂?strong>表單元素,例如文本輸入,廣播,選擇等。
由用戶輸入的數(shù)據(jù)以Http請求消息的形式通過GET或POST方法提交給服務(wù)器端腳本。
服務(wù)器端腳本必須從http請求數(shù)據(jù)重新創(chuàng)建表單元素。 因此,實際上,表單元素必須定義兩次 - 一次在HTML中,再次在服務(wù)器端腳本中。
使用HTML表單的另一個缺點是動態(tài)地呈現(xiàn)表單元素是困難的(如果不是不可能的話)。 HTML本身沒有提供驗證用戶輸入的方法。
這是 WTForms ,一個靈活的形式,渲染和驗證庫的地方很方便。 Flask-WTF擴展為這個 WTForms 庫提供了一個簡單的接口。
使用 Flask-WTF ,我們可以在Python腳本中定義表單字段,并使用HTML模板呈現(xiàn)它們。 也可以對 WTF 字段應(yīng)用驗證。
讓我們看看這個動態(tài)生成的HTML是如何工作的。
首先,需要安裝Flask-WTF擴展。
pip install flask-WTF
已安裝的軟件包包含一個 Form 類,必須用作用戶定義表單的父類。
WTforms 包中包含各種表單字段的定義。 下面列出了一些標準表單字段。
Sr.No | 標準表格字段&amp; 描述 |
---|---|
1 | TextField 表示&lt; input type =\'text\'&gt; HTML表單元素 |
2 | BooleanField 表示&lt; input type =\'checkbox\'&gt; HTML表單元素 |
3 | DecimalField 用于顯示帶小數(shù)的數(shù)字的文本框 |
4 | IntegerField 用于顯示整數(shù)的TextField |
5 | RadioField 表示&lt; input type =\'radio\'&gt; HTML表單元素 |
6 | SelectField 表示選擇表單元素 |
7 | TextAreaField 表示&lt; testarea&gt; html表單元素 |
8 | PasswordField 表示&lt; input type =\'password\'&gt; HTML表單元素 |
9 | SubmitField 表示&lt; input type =\'submit\'&gt; 表單元素 |
例如,包含文本字段的表單可以設(shè)計如下 -
from flask_wtf import Form from wtforms import TextField class ContactForm(Form): name = TextField("Name Of Student")
除了\'name\'字段,自動創(chuàng)建CSRF令牌的隱藏字段。 這是為了防止跨站點請求偽造攻擊。
呈現(xiàn)時,這將導(dǎo)致等效的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應(yīng)用程序中使用用戶定義的表單類,并使用模板呈現(xiàn)表單。
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包也包含驗證器類。 它在將驗證應(yīng)用于表單字段時很有用。 以下列表顯示常用的驗證器。
Sr.No | 驗證器類&amp; 描述 |
---|---|
1 | DataRequired 檢查輸入字段是否為空 |
2 | 電子郵件 檢查字段中的文本是否符合電子郵件ID約定 |
3 | IP地址 在輸入字段中驗證IP地址 |
4 | 長度 驗證輸入字段中的字符串長度是否在給定范圍內(nèi) |
5 | NumberRange 在給定范圍內(nèi)驗證輸入字段中的數(shù)字 |
6 | 網(wǎng)址 驗證在輸入字段中輸入的URL |
現(xiàn)在,我們將對聯(lián)系表單中的 name 字段應(yīng)用\'DataRequired\'驗證規(guī)則。
name = TextField("Name Of Student",[validators.Required("Please enter your name.")])
表單對象的 validate()函數(shù)驗證表單數(shù)據(jù),并在驗證失敗時拋出驗證錯誤。 錯誤消息將發(fā)送到模板。 在HTML模板中,錯誤消息是動態(tài)呈現(xiàn)的。
{% for message in form.name.errors %} {{ message }} {% endfor %}
以下示例演示了上面給出的概念。 聯(lián)系表單的設(shè)計如下(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")
驗證器會應(yīng)用到名稱和電子郵件字段。
下面給出了Flask應(yīng)用程序腳本(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 = "http://localhost: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 ,訪問URL http:// localhost:5000 / contact 。 將顯示聯(lián)系人表單,如下所示。
如果有任何錯誤,頁面將看起來像這樣 -
如果沒有錯誤,將顯示\'success.html\'。
Python具有對 SQlite 的內(nèi)置支持。 SQlite3模塊隨Python分發(fā)。 有關(guān)在Python中使用SQLite數(shù)據(jù)庫的詳細教程,請參閱此鏈接。 在本節(jié)中,我們將看到Flask應(yīng)用程序如何與SQLite交互。
創(chuàng)建SQLite數(shù)據(jù)庫\'database.db\'并在其中創(chuàng)建學(xué)生表。
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應(yīng)用程序有三個查看功能。
第一個 new_student()函數(shù)已綁定到網(wǎng)址規(guī)則(\'/ addnew\')。 它呈現(xiàn)包含學(xué)生信息表單的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>
可以看出,表單數(shù)據(jù)發(fā)布到綁定 addrec()函數(shù)的\'/ addrec\' URL。
此 addrec()函數(shù)通過 POST 方法檢索表單的數(shù)據(jù),并插入學(xué)生表中。 在插入操作中對應(yīng)于成功或錯誤的消息呈現(xiàn)到\'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腳本包含顯示插入操作結(jié)果的轉(zhuǎn)義語句 {{msg}} 。
<!doctype html> <html> <body> result of addition : {{ msg }} <h2><a href = "\">go back to home page</a></h2> </body> </html>
應(yīng)用程序包含由\'/ list\' URL表示的另一個 list()函數(shù)。 它將\'rows\'填充為包含學(xué)生表中所有記錄的 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表中呈現(xiàn)數(shù)據(jù)。
<!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>
最后,\'/\'網(wǎng)址規(guī)則呈現(xiàn)一個\'home.html\',作為應(yīng)用程序的入口點。
@app.route('/') def home(): return render_template('home.html')
這是 Flask-SQLite 應(yīng)用程序的完整代碼。
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)
在開發(fā)服務(wù)器開始運行時,從Python shell運行此腳本。 在瀏覽器中訪問 http:// localhost:5000 / ,顯示一個簡單的菜單 -
點擊“添加新記錄”鏈接以打開學(xué)生信息表單。
填寫表單字段并提交。 底層函數(shù)在學(xué)生表中插入記錄。
返回首頁,然后點擊\'顯示列表\'鏈接。 將顯示顯示樣品數(shù)據(jù)的表。
在Flask Web應(yīng)用程序中使用原始SQL對數(shù)據(jù)庫執(zhí)行CRUD操作可能很乏味。 相反, SQLAlchemy ,Python工具包是一個強大的 OR Mapper ,為應(yīng)用程序開發(fā)人員提供了SQL的全部功能和靈活性。 Flask-SQLAlchemy是Flask擴展,為SQLAlchemy應(yīng)用程序添加了對SQLAlchemy的支持。
什么是ORM(對象關(guān)系映射)?
大多數(shù)編程語言平臺是面向?qū)ο蟮摹?/span> 另一方面,RDBMS服務(wù)器中的數(shù)據(jù)存儲為表。 對象關(guān)系映射是將對象參數(shù)映射到底層RDBMS表結(jié)構(gòu)的技術(shù)。 ORM API提供了執(zhí)行CRUD操作的方法,而不必編寫原始SQL語句。
在本節(jié)中,我們將研究Flask-SQLAlchemy的ORM技術(shù)并構(gòu)建一個小型Web應(yīng)用程序。
步驟1 - 安裝Flask-SQLAlchemy擴充功能。
pip install flask-sqlalchemy
步驟2 - 您需要從此模塊導(dǎo)入SQLAlchemy類。
from flask_sqlalchemy import SQLAlchemy
步驟3 - 現(xiàn)在創(chuàng)建一個Flask應(yīng)用程序?qū)ο蟛⒃O(shè)置要使用的數(shù)據(jù)庫的URI。
app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'
步驟4 - 然后創(chuàng)建一個SQLAlchemy類的對象,以應(yīng)用程序?qū)ο笞鳛閰?shù)。 此對象包含用于ORM操作的輔助函數(shù)。 它還提供了一個父Model類,使用它來聲明用戶定義的模型。 在下面的代碼段中,創(chuàng)建了學(xué)生模型。
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 - 要創(chuàng)建/使用URI中提及的數(shù)據(jù)庫,請運行 create_all()方法。
db.create_all()
SQLAlchemy 的 Session 對象管理 ORM 對象的所有持久性操作。
以下會話方法執(zhí)行CRUD操作 -
db.session.add (模型對象) - 將記錄插入到映射表中
db.session.delete (模型對象) - 從表中刪除記錄
model.query.all() - 從表中檢索所有記錄(對應(yīng)于SELECT查詢)。
您可以通過使用filter屬性將過濾器應(yīng)用于檢索的記錄集。 例如,要在學(xué)生表中檢索 city =\'Hyderabad\'的記錄,請使用以下語句 -
Students.query.filter_by(city = ’Hyderabad’).all()
有了這么多的背景,現(xiàn)在我們將提供視圖函數(shù)為我們的應(yīng)用程序添加學(xué)生數(shù)據(jù)。
應(yīng)用程序的入口點是綁定到\'/\' URL的 show_all()函數(shù)。 學(xué)生記錄集表作為參數(shù)發(fā)送到HTML模板。 模板中的服務(wù)器端代碼以HTML表格形式呈現(xiàn)記錄。
@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>
上述網(wǎng)頁包含指向\'/ new\'網(wǎng)址映射 new()函數(shù)的超鏈接。 單擊時,將打開“學(xué)生信息”表單。 數(shù)據(jù)在 POST 方法中發(fā)布到相同的URL。
<!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時,表單數(shù)據(jù)被添加到學(xué)生表中,并且應(yīng)用返回到顯示添加的數(shù)據(jù)的主頁。
@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')
下面給出了應(yīng)用程序(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運行腳本,并在瀏覽器中輸入 http:// localhost:5000 / 。
點擊“添加學(xué)生”鏈接以打開學(xué)生信息表單。
填寫表單并提交。 主頁將重新顯示提交的數(shù)據(jù)。
我們可以看到輸出如下所示。
Sijax 代表\'Simple Ajax\',它是一個 Python / jQuery 庫,旨在幫助您輕松地將 Ajax 到您的應(yīng)用程序。 它使用 jQuery.ajax 來創(chuàng)建AJAX請求。
安裝Flask-Sijax很容易。
pip install flask-sijax
SIJAX_STATIC_PATH - 您希望對Sijax javascript文件進行鏡像的靜態(tài)路徑。 默認位置為 static / js / sijax 。 在此文件夾中,保存 sijax.js 和 json2.js 文件。
SIJAX_JSON_URI - 用于加載json2.js靜態(tài)文件的URI
Sijax使用 JSON 在瀏覽器和服務(wù)器之間傳遞數(shù)據(jù)。 這意味著瀏覽器需要或從 json2.js 文件本身支持 JSON 或獲取 JSON 支持。
以此方式注冊的函數(shù)不能提供 Sijax 功能,因為它們在默認情況下不能使用 POST 方法訪問(而Sijax使用POST請求)。
要使 View 功能能夠處理 Sijax 請求,請使用 @ app.route(\'/ url\',methods = [\'GET\' ,\'POST\'])或使用 @ flask_sijax.route 輔助裝飾器,
@flask_sijax.route(app, '/hello')
每個Sijax處理函數(shù)(像這樣)至少接收一個參數(shù),就像Python傳遞\'self\'到對象方法。 \'obj_response\'參數(shù)是函數(shù)回傳瀏覽器的方式。
def say_hi(obj_response): obj_response.alert('Hi there!')
當檢測到Ajax請求時,Sijax處理它像這樣 -
g.sijax.register_callback('say_hi', say_hi) return g.sijax.process_request()
最小的Sijax應(yīng)用程序代碼如下 -
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向服務(wù)器請求(特殊的 jQuery.ajax()請求)時,此請求在服務(wù)器上通過 g.sijax.is_sijax_request()檢測到, case你讓 Sijax 處理請求。
使用 g.sijax.register_callback()注冊的所有函數(shù)都可以從瀏覽器調(diào)用。
調(diào)用 g.sijax.process_request()會告訴Sijax執(zhí)行相應(yīng)的(先前注冊的)函數(shù)并將響應(yīng)返回給瀏覽器。
開發(fā)服務(wù)器上的Flask應(yīng)用程序只能在設(shè)置開發(fā)環(huán)境的計算機上訪問。 這是一種默認行為,因為在調(diào)試模式下,用戶可以在計算機上執(zhí)行任意代碼。
如果禁用了 debug ,則可以通過將主機名設(shè)置為\'0.0.0.0\',使本地計算機上的開發(fā)服務(wù)器對網(wǎng)絡(luò)上的用戶可用。
app.run(host = ’0.0.0.0’)
因此,您的操作系統(tǒng)偵聽所有公共IP。
要從開發(fā)環(huán)境切換到完整的生產(chǎn)環(huán)境,應(yīng)用程序需要部署在真實的Web服務(wù)器上。 根據(jù)您的具體情況,有不同的選項可用于部署Flask Web應(yīng)用程序。
對于小型應(yīng)用程序,您可以考慮將其部署到以下任何托管平臺上,所有這些平臺都為小型應(yīng)用程序提供免費計劃。
Flask應(yīng)用程序可以部署在這些云平臺上。 此外,可以在Google云平臺上部署Flask應(yīng)用程序。 Localtunnel服務(wù)允許您在localhost上共享您的應(yīng)用程序,而不會破壞DNS和防火墻設(shè)置。
如果您傾向于使用專用的Web服務(wù)器代替上述共享平臺,以下選項有待探索。
mod_wsgi 是一個Apache模塊,它提供了一個符合WSGI的接口,用于在Apache服務(wù)器上托管基于Python的Web應(yīng)用程序。
要直接從PyPi安裝官方發(fā)布,你可以運行 -
pip install mod_wsgi
要驗證安裝是否成功,請使用start-server命令運行mod_wsgi-express腳本 -
mod_wsgi-express start-server
這將啟動Apache / mod_wsgi在端口8000.然后您可以驗證安裝工作通過指向您的瀏覽器 -
http://localhost:8000/
應(yīng)該有一個 yourapplication.wsgi 文件。 此文件包含代碼 mod_wsgi,,它在啟動時執(zhí)行以獲取應(yīng)用程序?qū)ο蟆?/span> 對于大多數(shù)應(yīng)用程序,以下文件應(yīng)該足夠 -
from yourapplication import app as application
確保 yourapplication 和所有正在使用的庫都在python加載路徑。
您需要告訴 mod_wsgi,您的應(yīng)用程序的位置。
<VirtualHost *> ServerName example.com WSGIScriptAlias / C:\yourdir\yourapp.wsgi <Directory C:\yourdir> Order deny,allow Allow from all </Directory> </VirtualHost>
有許多使用Python編寫的流行服務(wù)器,它們包含WSGI應(yīng)用程序和服務(wù)HTTP。
FastCGI是在像nginx,lighttpd和Cherokee這樣的web服務(wù)器上的Flask應(yīng)用程序的另一個部署選項。
首先,您需要創(chuàng)建 FastCGI 服務(wù)器文件。 讓我們將其稱為 yourapplication.fcgiC 。
from flup.server.fcgi import WSGIServer from yourapplication import app if __name__ == '__main__': WSGIServer(app).run()
nginx 和舊版本的 lighttpd 需要一個套接字以明確傳遞,以便與 FastCGI 服務(wù)器通信。 要使其工作,您需要將路徑傳遞到 WSGIServer 的套接字。
WSGIServer(application, bindAddress = '/path/to/fcgi.sock').run()
對于基本的Apache部署,您的 .fcgi 文件將顯示在應(yīng)用程序網(wǎng)址中。 example.com/yourapplication.fcgi/hello / 。 有幾種方法可以配置您的應(yīng)用程序,以使 yourapplication.fcgi 不會顯示在網(wǎng)址中。
<VirtualHost *> ServerName example.com ScriptAlias / /path/to/yourapplication.fcgi/ </VirtualHost>
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 ,別名和重寫模塊。 此配置將應(yīng)用程序綁定到 / yourapplication 。
更多建議: