### 導航
- [索引](# "總目錄")
- [下一頁](# "教程") |
- [上一頁](# "安裝") |
- [Flask 0.10.1 文檔](#) ?
# 快速入門
迫不及待要開始了嗎?本頁提供了一個很好的 Flask 介紹,并假定你已經安裝好了 Flask。如果沒有,請跳轉到 [*安裝*](#) 章節。
### 一個最小的應用
一個最小的 Flask 應用看起來是這樣:
~~~
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
~~~
把它保存為 hello.py (或是類似的),然后用 Python 解釋器來運行。但是確保你的應用沒有命名為 flask.py ,因為這將與 Flask 本身沖突。
~~~
$ python hello.py
* Running on http://127.0.0.1:5000/
~~~
現在訪問 [http://127.0.0.1:5000/](http://127.0.0.1:5000/) ,你會看見 hello world 問候。
那么,這段代碼做了什么?
1. 首先,我們導入了 [Flask](# "flask.Flask") 類。這個類的實例將會是我們的 WSGI 應用程序。
1. 接下來,我們創建一個該類的實例,第一個參數是應用模塊或者包的名稱。如果你使用單一的模塊(如本例),你應該使用 __name__ ,因為取決于作為單獨應用啟動或者模塊導入,它的名稱將會不同( '__main__'相對實際的導入名稱)。這是必須的,這樣Flask 才會知道到哪里去尋找模板、靜態文件等等。詳情參見 [Flask](# "flask.Flask") 的文檔。
1. 然后,我們使用 [route()](# "flask.Flask.route") 裝飾器告訴 Flask 什么樣的URL 應該觸發我們的函數。
1. 這個函數的名字也用作給特定的函數生成 URL,并且返回我們想要顯示在用戶瀏覽器中的信息。
1. 最后我們用 [run()](# "flask.Flask.run") 函數來讓應用運行在本地服務器上。其中 if__name__=='__main__': 確保服務器只會在該腳本被Python 解釋器直接執行的時候才會運行,而不是作為模塊導入的時候。
要停止服務器,按 Ctrl+C。
可外部訪問的服務器
如果你運行服務器,你會注意到它只能從你自己的計算機上訪問,網絡中其它任何的地方都不能訪問。這是在默認情況,因為在調試模式,用戶可以在你的計算機上執行任意 Python 代碼。
如果你禁用了 debug 或信任你所在網絡的用戶,你可以簡單修改調用[run()](# "flask.Flask.run") 的方法使你的服務器公開可用,如下:
~~~
app.run(host='0.0.0.0')
~~~
這會讓操作系統監聽所有公開的IP。
### 調試模式
雖然 [run()](# "flask.Flask.run") 方法適用于本地開發服務器的啟動,但是你每次修改代碼后都要手動重啟它。這樣并不是很好,然而 Flask 可以做得更好。如果你啟用了調試 支持,服務器會在代碼變更時自動重新載入,并且如果發生錯誤,它會提供一個有用的調試器。
有兩種途徑來啟用調試模式。一種是在應用對象上設置:
~~~
app.debug = True
app.run()
~~~
另一種是作為 run 方法的一個參數傳入:
~~~
app.run(debug=True)
~~~
兩種方法的效果完全相同。
注意
盡管交互式調試器不能在 forking 環境(即在生產服務器上使用幾乎是不可能的),它依然允許執行任意代碼。這使它成為一個巨大的安全隱患,因此它 **絕對不能用于生產環境** 。
運行中的調試器截圖:

想用另一個調試器? 參見 [*調試器操作*](#) 。
### 路由
現代 web 應用使用優雅的 URL,這易于人們記住 URL ,這點在面向使用慢網絡連接的移動設備的應用上特別有用。如果可以不訪問索引頁而直接訪問想要的頁面,他們多半會喜歡這個頁面而再度光顧。
如上所見, [route()](# "flask.Flask.route") 裝飾器把一個函數綁定到對應的 URL 上。這里是一些基本的例子:
~~~
@app.route('/')
def index():
return 'Index Page'
@app.route('/hello')
def hello():
return 'Hello World'
~~~
但是,不僅如此!你可以構造特定部分動態的 URL,也可以在一個函數上附加多個規則。
### 變量規則
要給 URL 添加變量部分,你可以把這些特殊的字段標記為 <variable_name> ,這個部分將會作為命名參數傳遞到你的函數。規則可以用<converter:variable_name> 指定一個可選的轉換器。這里有一些不錯的例子:
~~~
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
@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
~~~
現有的轉換器如下:
| int | 接受整數 |
|-----|-----|
| float | 同 int ,但是接受浮點數 |
| path | 和默認的相似,但也接受斜線 |
唯一的網址 / 重定向行為
Flask 的 URL 規則基于 Werkzeug 的路由模塊。這個模塊背后的思想是基于 Apache以及更早的 HTTP 服務器規定的先例,保證優雅且唯一的 URL。
以這兩個規則為例:
~~~
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
~~~
雖然它們看起來確實相似,但它們結尾斜線的使用在 URL *定義* 中不同。第一種情況中,規范的 URL 指向 projects 尾端有一個斜線。這種感覺很像在文件系統中的文件夾。訪問一個結尾不帶斜線的 URL 會被Flask 重定向到帶斜線的規范 URL 去。
然而,第二種情況的 URL 結尾不帶斜線,類似 UNIX-like 系統下的文件的路徑名。訪問結尾帶斜線的 URL 會產生一個 404 “Not Found” 錯誤。
當用戶訪問頁面時忘記結尾斜線時,這個行為允許關聯的 URL 繼續工作,并且與 Apache 和其它的服務器的行為一致。另外,URL 會保持唯一,有助于避免搜索引擎索引同一個頁面兩次。
### 構建 URL
如果它能匹配 URL ,那么 Flask 可以生成它們嗎?當然可以。你可以使用[url_for()](# "flask.url_for") 來給一個特定函數構造 URL。它接受一個函數名作為第一個參數和一些關鍵字參數,每個對應 URL 規則的變量部分。未知變量部分會添加到 URL 末尾作為查詢參數。這里是一些例子:
~~~
>>> from flask import Flask, url_for
>>> app = Flask(__name__)
>>> @app.route('/')
... def index(): pass
...
>>> @app.route('/login')
... def login(): pass
...
>>> @app.route('/user/<username>')
... def profile(username): pass
...
>>> with app.test_request_context():
... print url_for('index')
... print url_for('login')
... print url_for('login', next='/')
... print url_for('profile', username='John Doe')
...
/
/login
/login?next=/
/user/John%20Doe
~~~
(這里也用到了 [test_request_context()](# "flask.Flask.test_request_context") 方法,下面會解釋。即使我們正在通過 Python 的 shell 進行交互,它依然會告訴 Flask 像對待請求一樣處理。請看下面的解釋。 [*局部上下文*](#) )
為什么你會想要構建 URL 而非在模板中硬編碼?這里有三個好理由:
1. 反向構建通常比硬編碼更具備描述性。更重要的是,它允許你一次性修改 URL,而不是到處找 URL 改。
1. URL 構建會顯式地處理特殊字符和 Unicode 數據的轉義,所以你不需要親自處理。
1. 如果你的應用不位于 URL 的根路徑(比如,在 /myapplication 而不是 /), [url_for()](# "flask.url_for") 會為你妥善地處理這些。
### HTTP 方法
HTTP (web 應用會話的協議)知道訪問 URL 的不同方法。默認情況下,路由只回應GET 請求,但是通過給 [route()](# "flask.Flask.route") 裝飾器提供 methods 參數可以更改這個行為。這里有一些例子:
~~~
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
do_the_login()
else:
show_the_login_form()
~~~
如果當前是 GET 請求, 它也會自動的為你添加`HEAD`,無需你操心。它會確保 HEAD請求按照 [HTTP RFC](http://www.ietf.org/rfc/rfc2068.txt) [http://www.ietf.org/rfc/rfc2068.txt] (描述 HTTP 協議的文檔)來處理,所以你可以完全忽略這部分的 HTTP 規范。同樣,自從 Flask 0.6 起, OPTIONS 也實現了自動處理。
你不知道一個 HTTP 方法是什么?不必擔心,這里快速介紹 HTTP 方法和它們為什么重要:
HTTP 方法(也經常被叫做“謂詞”)告訴服務器客戶端想對請求的頁面 *做* 什么。以下都是非常常見的方法:
GET瀏覽器告訴服務器,只 *獲取* 頁面上的信息并發給我。這是最常用的方法。HEAD瀏覽器告訴服務器獲取信息,但是只對 *消息頭* 感興趣。應用期望像 GET 請求一樣處理它,但是不傳遞實際內容。在 Flask 中你完全不用處理它,底層的Werkzeug 庫已經替你處理好了。POST瀏覽器告訴服務器,它想在 URL 上 *發布* 新信息。并且,服務器必須確保數據已存儲且只存儲一次。這是 HTML 表單通常發送數據到服務器的方法。PUT類似 POST 但是服務器可能觸發了存儲過程多次,多次覆蓋掉舊值。你可能會問這有什么用,當然這是有原因的。考慮到傳輸中連接可能會丟失,在這種情況下瀏覽器和服務器之間的系統可能安全地第二次接收請求,而不破壞其它東西。使用 POST不能實現,因為它只會被觸發一次。DELETE刪除給定位置的信息。OPTIONS給客戶端提供一個快速的途徑來弄清這個 URL 支持哪些 HTTP 方法。從 Flask 0.6 開始,自動實現了它。
有趣的是,在 HTML4 和 XHTML1 中,表單只能以 GET 和 POST 方法提交到服務器。但是用 JavaScript 和未來的 HTML 標準允許你使用其它所有的方法。此外,HTTP 最近變得相當流行,瀏覽器不再是唯一的 HTTP 客戶端。例如,許多版本控制系統也在用它。
### 靜態文件
動態 web 應用也會需要靜態文件,通常是 CSS 和 JavaScript 文件的存放位置。理想情況下,你已經配置 web 服務器來提供它們,但是在開發中, Flask 也可以做到。只要在你的包中或模塊旁邊創建一個名為 static 的文件夾,在應用中使用 /static 即可訪問。
給靜態文件生成 URL ,使用特殊的 'static' 端點名:
~~~
url_for('static', filename='style.css')
~~~
這個文件應該存儲在文件系統上的 static/style.css 。
### 模板渲染
在 Python 里生成 HTML 十分無趣,而且相當繁瑣,因為你需要自行對 HTML 做轉義來保證應用安全。由于這個原因, Flask 自動配置了[Jinja2](http://jinja.pocoo.org/2/) [http://jinja.pocoo.org/2/] 模板引擎。
你可以使用 [render_template()](# "flask.render_template") 方法來渲染模板。你需要做的所有事就是將模板名和你想作為關鍵字的參數傳入模板的變量。這里有一個描述如何渲染模板的簡例:
~~~
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
~~~
Flask 會在 templates 文件夾里尋找模板。所以,如果你的應用是個模塊,這個文件夾在模塊的旁邊;如果它是一個包,那么這個文件夾在你的包里面:
**情況 1**: 模塊:
~~~
/application.py
/templates
/hello.html
~~~
**情況 2**: 包:
~~~
/application
/__init__.py
/templates
/hello.html
~~~
對于模板,你可以使用 Jinja2 模板的全部能力。更多信息請見官方的 [Jinja2 模板文檔](http://jinja.pocoo.org/2/documentation/templates) [http://jinja.pocoo.org/2/documentation/templates] 。
這里是一個模板實例:
~~~
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello World!</h1>
{% endif %}
~~~
在模板里,你也可以訪問 [request](# "flask.request") 、 [session](# "flask.session") 和[g](# "flask.g")[[1]](#) 對象,以及 [get_flashed_messages()](# "flask.get_flashed_messages") 函數。
使用繼承,模板會相當有用。如果你想知道繼承如何工作,請跳轉到[*模板繼承*](#) 模式文檔。基本的模板繼承使得特定元素(比如頁眉、導航欄和頁腳)可以出現在所有的頁面。
自動轉義默認是開啟的,所以如果 name 包含 HTML ,它將會被自動轉義。如果你能信任一個變量,并且你知道它是安全的(例如一個模塊把 wiki 標記轉換到 HTML ),你可以用Markup 類或 |safe 過濾器在模板中標記它是安全的。在 Jinja 2文檔中,你會見到更多例子。
這里是一個 Markup 類如何工作的基本介紹:
~~~
>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello <blink>hacker</blink>!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'<blink>hacker</blink>')
>>> Markup('<em>Marked up</em> » HTML').striptags()
u'Marked up \xbb HTML'
~~~
在 0.5 版更改: 自動轉義不再在所有模板中啟用。下列擴展名的模板會觸發自動轉義: .html 、.htm 、.xml 、 .xhtml 。從字符串加載的模板會禁用自動轉義。
| [[1]](#) | 不確定 [g](# "flask.g") 對象是什么?它是你可以按需存儲信息的東西,查看( [g](# "flask.g") )對象的文檔和 [*在 Flask 中使用 SQLite 3*](#) 的文檔以獲取更多信息。 |
|-----|-----|
### 訪問請求數據
對于 web 應用,對客戶端發送給服務器的數據做出反應至關重要。在 Flask 中由全局的 [request](# "flask.request") 對象來提供這些信息。如果你有一定的 Python 經驗,你會好奇這個對象怎么可能是全局的,并且 Flask 是怎么還能保證線程安全。答案是上下文作用域:
### 局部上下文
內幕
如果你想理解它是如何工作以及如何實現測試,請閱讀此節,否則可跳過。
Flask 中的某些對象是全局對象,但不是通常的類型。這些對象實際上是給定上下文的局部對象的代理。雖然很拗口,但實際上很容易理解。
想象一下處理線程的上下文。一個請求傳入,web 服務器決定生成一個新線程(或者別的什么東西,只要這個基礎對象可以勝任并發系統,而不僅僅是線程)。當 Flask 開始它內部請求處理時,它認定當前線程是活動的上下文并綁定當前的應用和 WSGI 環境到那個上下文(線程)。它以一種智能的方法來實現,以保證一個應用調用另一個應用時不會中斷。
所以這對你來說意味著什么?除非你要做類似單元測試的東西,基本上可以完全忽略這種情況。你會發現依賴于一個請求對象的代碼會突然中斷,因為不會有請求對象。解決方案是自己創建一個請求對象并且把它綁定到上下文。單元測試的最早的解決方案是使用 [test_request_context()](# "flask.Flask.test_request_context") 上下文管理器。結合 with 聲明,它將綁定一個測試請求來進行交互。這里是一個例子:
~~~
from flask import request
with app.test_request_context('/hello', method='POST'):
# now you can do something with the request until the
# end of the with block, such as basic assertions:
assert request.path == '/hello'
assert request.method == 'POST'
~~~
另一種可能是傳遞整個 WSGI 環境給 [request_context()](# "flask.Flask.request_context") 方法:
~~~
from flask import request
with app.request_context(environ):
assert request.method == 'POST'
~~~
### 請求對象
請求對象在 API 章節有詳細的描述(參見 [request](# "flask.request") ),這里不會贅述。這里寬泛介紹一些最常用的操作。首先你需要從 flask 模塊里導入它:
~~~
from flask import request
~~~
當前的請求方式通過 method 屬性來訪問。通過form 屬性來訪問表單數據( POST 或 PUT 請求提交的數據)。這里有一個上面提到的兩個屬性的完整實例:
~~~
@app.route('/login', methods=['POST', 'GET'])
def login():
error = None
if request.method == 'POST':
if valid_login(request.form['username'],
request.form['password']):
return log_the_user_in(request.form['username'])
else:
error = 'Invalid username/password'
# the code below is executed if the request method
# was GET or the credentials were invalid
return render_template('login.html', error=error)
~~~
當 form 屬性中的鍵值不存在會發生什么?在這種情況,一個特殊的[KeyError](http://docs.python.org/dev/library/exceptions.html#KeyError "(在 Python v3.5)") [http://docs.python.org/dev/library/exceptions.html#KeyError] 異常會拋出。你可以像捕獲標準的 [KeyError](http://docs.python.org/dev/library/exceptions.html#KeyError "(在 Python v3.5)") [http://docs.python.org/dev/library/exceptions.html#KeyError] 來捕獲它。如果你不這么做,它會顯示一個 HTTP 400 Bad Request 錯誤頁面。所以,很多情況下你并不需要處理這個問題。
你可以通過 args 屬性來訪問 URL 中提交的參數( ?key=value ):
~~~
searchword = request.args.get('q', '')
~~~
我們推薦使用 get 來訪問 URL 參數或捕獲 KeyError ,因為用戶可能會修改 URL ,向他們展現一個 400 bad request 頁面會影響用戶體驗。
想獲取請求對象的完整方法和屬性清單,請參閱 [request](# "flask.request") 的文檔。
### 文件上傳
你可以很容易的用 Flask 處理文件上傳。只需要確保沒忘記在你的 HTML 表單中設置enctype="multipart/form-data" 屬性,否則你的瀏覽器將根本不提交文件。
已上傳的文件存儲在內存或是文件系統上的臨時位置。你可以通過請求對象的files 屬性訪問那些文件。每個上傳的文件都會存儲在那個字典里。它表現得如同一個標準的 Python file 對象,但它還有一個[save()](http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.save "(在 Werkzeug v0.10)") [http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.save] 方法來允許你在服務器的文件系統上保存它。這里是一個它如何工作的例子:
~~~
from flask import request
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/uploaded_file.txt')
...
~~~
如果你想知道上傳前文件在客戶端的文件名,你可以訪問[filename](http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.filename "(在 Werkzeug v0.10)") [http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.filename] 屬性。但請記住永遠不要信任這個值,因為這個值可以偽造。如果你想要使用客戶端的文件名來在服務器上存儲文件,把它傳遞給 Werkzeug 提供的[secure_filename()](http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename "(在 Werkzeug v0.10)") [http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename] 函數:
~~~
from flask import request
from werkzeug import secure_filename
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/' + secure_filename(f.filename))
...
~~~
一些更好的例子,查看 [*上傳文件*](#) 模式。
### Cookies
你可以通過 [cookies](# "flask.Request.cookies") 屬性來訪問 cookies 。設置cookies 通過響應對象的 [set_cookie](# "flask.Response.set_cookie") 方法。請求對象的 [cookies](# "flask.Request.cookies") 屬性是一個客戶端提交的所有 cookies 的字典。如果你想使用會話,請不要直接使用 cookies,請參考 [*會話*](#)一節。在 Flask 中,已經在 cookies 上增加了一些安全細節。
讀取 cookies:
~~~
from flask import request
@app.route('/')
def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
~~~
存儲 cookies:
~~~
from flask import make_response
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
~~~
注意 cookies 是設置在響應對象上。由于通常只是從視圖函數返回字符串,Flask 會將其轉換為響應對象。如果你顯式地想要這么做,你可以使用[make_response()](# "flask.make_response") 函數然后修改它。
有時候你會想要在響應對象不存在的時候設置 cookie ,這在利用[*延遲請求回調*](#) 模式時是可行的。
為此也可以參閱 [*關于響應*](#) 。
### 重定向和錯誤
重定向用戶到其它地方你可以使用 [redirect()](# "flask.redirect") 函數。放棄請求并返回錯誤代碼可以使用 [abort()](# "flask.abort") 函數。這里是一個它們如何工作的例子:
~~~
from flask import abort, redirect, url_for
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
abort(401)
this_is_never_executed()
~~~
這是一個相當無意義的例子因為用戶會從主頁重定向到一個不能訪問的頁面(401意味著禁止訪問),但是它說明了重定向如何工作。
默認情況下,每個錯誤代碼會顯示一個黑白錯誤頁面。如果你想定制錯誤頁面,可以使用 [errorhandler()](# "flask.Flask.errorhandler") 裝飾器:
~~~
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
~~~
注意 [render_template()](# "flask.render_template") 調用之后的 404 。這告訴 Flask 該頁的錯誤代碼應是 404 ,即沒有找到。默認的 200 被假定為:一切正常。
### 關于響應
視圖函數的返回值會被自動轉換為一個響應對象。如果返回值是一個字符串,它被轉換為響應主體為該字符串、狀態碼為 200OK 、 MIME 類型為text/html 的響應對象。Flask 把返回值轉換為響應對象的邏輯如下:
1. 如果返回的是一個合法的響應對象,它會被從視圖直接返回。
1. 如果返回的是一個字符串,響應對象會用字符串數據和默認參數創建。
1. 如果返回的是一個元組,且元組中的元素可以提供額外的信息。這樣的元組必須是 (response,status,headers) 這樣的形式,且至少包含一個元素。status 值會覆蓋狀態代碼, headers 可以是一個列表或字典,作為額外的消息頭值。
1. 如果上述條件均不滿足, Flask 會假設返回值是一個合法的 WSGI 應用程序,并轉換為一個請求對象。
如果你想在視圖里掌控上述步驟結果的響應對象,你可以使用[make_response()](# "flask.make_response") 函數。
想象你有這樣一個視圖:
~~~
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
~~~
你只需要用 [make_response()](# "flask.make_response") 封裝返回表達式,獲取結果對象并修改,然后返回它:
~~~
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
~~~
### 會話
除請求對象之外,還有 [session](# "flask.session") 對象允許你在不同請求間存儲特定用戶的信息。這是在 cookies 的基礎上實現的,并且在 cookies 中使用加密的簽名。這意味著用戶可以查看你 cookie 的內容,但是不能修改它,除非它知道簽名的密鑰。
要使用會話,你需要設置一個密鑰。這里介紹會話如何工作:
~~~
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
@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><input type=submit value=Login>
</form>
'''
@app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
~~~
這里提到的 [escape()](# "flask.escape") 可以在你不使用模板引擎的時候做轉義(如同本例)。
如何生成一個強壯的密鑰
隨機的問題在于很難判斷什么是真隨機。一個密鑰應該足夠隨機。你的操作系統可以基于一個密碼隨機生成器來生成漂亮的隨機值,這個值可以用來做密鑰:
~~~
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
~~~
把這個值復制粘貼到你的代碼,你就搞定了密鑰。
使用基于 cookie 的會話需注意: Flask 會將你放進會話對象的值序列化到 cookie。如果你發現某些值在請求之間并沒有持久化保存,而 cookies 確實已經啟用了,你也沒有得到明確的錯誤信息,請檢查你的頁面響應中的 cookie 的大小,并與 web 瀏覽器所支持的大小對比。
### 消息閃現
良好的應用和用戶界面全部涉及反饋。如果用戶得不到足夠的反饋,他們很可能開始厭惡這個應用。 Flask 提供一種消息閃現系統給用戶反饋的簡單方法。消息閃現系統通常會在請求結束時記錄信息,并在下一個(且僅在下一個)請求中訪問。通常結合模板布局來展現消息。
使用 [flash()](# "flask.flash") 方法可以閃現一條消息。要掌控消息本身,使用[get_flashed_messages()](# "flask.get_flashed_messages") 函數,并且在模板中也可以使用。完整的例子請查閱 [*消息閃現*](#) 部分。
### 日志記錄
0.3 新版功能.
有時候你處于一種境地,你處理的數據本應該是正確的,但實際上不是。比如你有一些客戶端代碼向服務器發送請求,但請求顯然是畸形的。這可能是用戶篡改了數據,或是客戶端代碼的失敗。大多數情況下,正常地返回 400BadRequest 就可以了,但是有時不這么做,并且代碼要繼續運行。
你可能依然想要記錄發生了什么不對勁。這時日志記錄就派上了用場。Flask 0.3開始已經預置了日志系統。
這里有一些日志調用的例子:
~~~
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
~~~
附帶的 [logger](# "flask.Flask.logger") 是一個標準日志類[Logger](http://docs.python.org/dev/library/logging.html#logging.Logger "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Logger] ,所以更多信息請見 [logging文檔](http://docs.python.org/library/logging.html) [http://docs.python.org/library/logging.html] 。
### 整合 WSGI 中間件
如果你想給你的應用添加 WSGI 中間件,你可以封裝內部 WSGI 應用。例如如果你想使用 Werkzeug 包中的某個中間件來應付 lighttpd 中的 bugs ,可以這樣做:
~~~
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
~~~
### 部署到 Web 服務器
準備好部署你的 Flask 應用了?你可以立即部署到托管平臺來圓滿完成快速入門,以下均向小項目提供免費的方案:
- [在 Heroku 上部署 Flask](http://devcenter.heroku.com/articles/python) [http://devcenter.heroku.com/articles/python]
- [在 dotCloud 上部署 Flask](http://docs.dotcloud.com/services/python/) [http://docs.dotcloud.com/services/python/]附 [Flask 的具體說明](http://flask.pocoo.org/snippets/48/) [http://flask.pocoo.org/snippets/48/]
托管 Flask 應用的其它選擇:
- [在 Webfaction 上部署 Flask](http://flask.pocoo.org/snippets/65/) [http://flask.pocoo.org/snippets/65/]
- [在 Google App Engine 上部署 Flask](https://github.com/kamalgill/flask-appengine-template) [https://github.com/kamalgill/flask-appengine-template]
- [用 Localtunnel 共享你的本地服務器](http://flask.pocoo.org/snippets/89/) [http://flask.pocoo.org/snippets/89/]
如果你管理自己的主機并且想要親自運行,參見 [*部署選擇*](#) 章節。
? 版權所有 2013, Armin Ronacher.
- 歡迎使用 Flask
- 前言
- 給有經驗程序員的前言
- 安裝
- 快速入門
- 教程
- 介紹 Flaskr
- 步驟 0: 創建文件夾
- 步驟 1: 數據庫模式
- 步驟 2: 應用設置代碼
- 步驟 3: 創建數據庫
- 步驟 4: 請求數據庫連接
- 步驟 5: 視圖函數
- 步驟 6: 模板
- 步驟 7: 添加樣式
- 福利: 應用測試
- 模板
- 測試 Flask 應用
- 記錄應用錯誤
- 配置處理
- 信號
- 即插視圖
- 應用上下文
- 請求上下文
- 用藍圖實現模塊化的應用
- Flask 擴展
- 與 Shell 共舞
- Flask 代碼模式
- 大型應用
- 應用程序的工廠函數
- 應用調度
- 使用 URL 處理器
- 部署和分發
- 使用 Fabric 部署
- 在 Flask 中使用 SQLite 3
- 在 Flask 中使用 SQLAlchemy
- 上傳文件
- 緩存
- 視圖裝飾器
- 使用 WTForms 進行表單驗證
- 模板繼承
- 消息閃現
- 用 jQuery 實現 Ajax
- 自定義錯誤頁面
- 延遲加載視圖
- 在 Flask 中使用 MongoKit
- 添加 Favicon
- 數據流
- 延遲請求回調
- 添加 HTTP Method Overrides
- 請求內容校驗碼
- 基于 Celery 的后臺任務
- 部署選擇
- mod_wsgi (Apache)
- 獨立 WSGI 容器
- uWSGI
- FastCGI
- CGI
- 聚沙成塔
- API
- JSON 支持
- Flask 中的設計決策
- HTML/XHTML 常見問題
- 安全注意事項
- Flask 中的 Unicode
- Flask 擴展開發
- Pocoo 風格指引
- Python 3 支持
- 升級到最新版本
- Flask Changelog
- 許可證
- 術語表