flask.pocoo.org/docs/0.12/quickstart/#——翻譯

快速啟動(dòng)

是不是很渴望馬上開(kāi)始???這篇文檔將會(huì)很好的向你介紹Flask。假設(shè)你已經(jīng)安裝好了Flask。如果還沒(méi)有安裝的話,
請(qǐng)查看Installation部分。

一個(gè)小型的應(yīng)用

一個(gè)很小型的Flask應(yīng)用是像下面這樣的:

from flask import Flask
app = Flask(__name__)

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

上面的代碼做了什么呢?

1. 首先,我們引入了**Flask**類(lèi),創(chuàng)建這個(gè)類(lèi)的一個(gè)實(shí)例,這個(gè)實(shí)例將會(huì)成為我們的WSGI應(yīng)用。
2. 接下來(lái),我們創(chuàng)建了這個(gè)類(lèi)的實(shí)例,第一個(gè)參數(shù)是這個(gè)應(yīng)用的包名或者模塊名。
    如果你只是使用了一個(gè)模塊(就像這個(gè)例子一樣),你應(yīng)該使用**__name__**作為參數(shù),
    因?yàn)楦鶕?jù)模塊是作為程序運(yùn)行,或者是作為包被引入,它的名字是變化的('__main__' versus the actual import name),
    這個(gè)是必須的,因?yàn)镕lask由此知道去哪里尋找模板、靜態(tài)文件等等。更多信息請(qǐng)查看[Flask](http://flask.pocoo.org/docs/0.12/api/#flask.Flask)
3. 我們使用**route()**裝飾器去告訴Flask,什么樣的URL觸發(fā)哪一個(gè)函數(shù)。
4. 該函數(shù)的給出一個(gè)名稱,也生成該特定函數(shù)的URL,并返回我們要在用戶瀏覽器中顯示的消息。    

hello.py 保存這個(gè)文件,或者其他類(lèi)似的名字也可以,確保它的文件名不是 flask.py ,因?yàn)檫@樣會(huì)和Flask自己產(chǎn)生沖突。

為了運(yùn)行這個(gè)程序,一種方法是使用flask命令,另一種方法是python's -m switch with Flask.
在這之前,你需要設(shè)置環(huán)境變量FLASK_APP,以此來(lái)告訴你的終端需要運(yùn)行的程序是哪個(gè)。

export FLASK_APP = hello.py
flask run
* Running on http://127.0.0.1:5000/

如果你的事Windows系統(tǒng),你需要使用set代替export。

另一種方法,你也可以使用python -m flask:

export FLASK_APP = hello.py
python -m flask run
* Running on http://127.0.0.1:5000/

這樣就建立了一個(gè)很簡(jiǎn)單的內(nèi)置服務(wù)器,足以測(cè)試使用了,但是不能用于生產(chǎn)環(huán)境。
關(guān)于部署相關(guān)的信息,請(qǐng)查看Deployment Options

現(xiàn)在請(qǐng)轉(zhuǎn)向http://127.0.0.1:5000/,你將會(huì)看到自己的hello world問(wèn)候!

外部可訪問(wèn)的服務(wù)器

如果你運(yùn)行上面的服務(wù),你會(huì)發(fā)現(xiàn)僅僅你自己的電腦可以訪問(wèn)這個(gè)服務(wù)器,互聯(lián)網(wǎng)上的其他電腦不能訪問(wèn)。
這是默認(rèn)值,因?yàn)樵谡{(diào)試模式下,應(yīng)用程序的用戶可以在計(jì)算機(jī)上執(zhí)行任意Python代碼。

如果你的調(diào)試模式是關(guān)閉的,或者你相信你網(wǎng)絡(luò)內(nèi)的用戶,你可以通過(guò)如下代碼使服務(wù)器在遠(yuǎn)程網(wǎng)絡(luò)內(nèi)可見(jiàn):

flask run --host=0.0.0.0

這將會(huì)告訴你的系統(tǒng),監(jiān)聽(tīng)所有公用的IP地址。

如果服務(wù)沒(méi)有啟動(dòng)怎么辦?

如果python -m flask失敗,或者flask不存在,可能會(huì)有多種原因?qū)е碌摹?br> 首先,你需要查看錯(cuò)誤信息。

舊版本的Flask

在0.11版本之前的Flask,會(huì)有不同的啟動(dòng)應(yīng)用的方式。簡(jiǎn)單地說(shuō),flask命令行不存在,
python -m flask也一樣不存在。在這樣的情況下,你有兩種選擇:一種是升級(jí)到新版本的Flask,
另一種是查看Development Server
文檔,選擇一個(gè)可用的啟動(dòng)方法。

無(wú)效的導(dǎo)入名稱

FLASK_APP環(huán)境變量是在flask run的時(shí)候,需要導(dǎo)入的模塊名稱。
如果模塊名稱不正確,您將在啟動(dòng)時(shí)收到導(dǎo)入錯(cuò)誤(或者當(dāng)您導(dǎo)航到應(yīng)用程序時(shí)啟用調(diào)試)。
它會(huì)告訴你它在嘗試引入什么,為什么發(fā)生錯(cuò)誤了。

最常見(jiàn)的錯(cuò)誤是打字錯(cuò)誤,或者沒(méi)有創(chuàng)建應(yīng)用對(duì)象。

調(diào)試模式

(想要記錄錯(cuò)誤和堆棧跟蹤?請(qǐng)參閱Applications Errors

flask腳本可以很好的啟動(dòng)一個(gè)本地的開(kāi)發(fā)環(huán)境,但是當(dāng)你的代碼有改動(dòng)的時(shí)候,你必須手動(dòng)重新啟動(dòng)服務(wù)器。
這樣就感覺(jué)不方便,F(xiàn)lask可以做的更好。

如果啟用了調(diào)試支持,代碼更改以后服務(wù)器將自動(dòng)重新載入代碼,如果出現(xiàn)問(wèn)題,它還將為您提供一個(gè)有用的調(diào)試器。

你可以在運(yùn)行前,通過(guò)設(shè)置FLASK_APP環(huán)境變量來(lái)啟動(dòng)調(diào)試模式。

$ export FLASK_APP=1
$ flask run

(在Windows環(huán)境下,需要使用set代替export)

上面代碼做了如下事情:

  1. 激活了調(diào)試器;
  2. 激活了自動(dòng)重新加載;
  3. 打開(kāi)了Flask應(yīng)用的調(diào)試模式。

Development Server文檔中詳細(xì)解釋了更多的參數(shù)。

注意

即使交互式調(diào)試器在分支環(huán)境中不起作用(這使得幾乎不可能在生產(chǎn)服務(wù)器上使用)。
它仍然允許執(zhí)行任意代碼。這使得它成為主要的安全風(fēng)險(xiǎn),因此絕不能在生產(chǎn)環(huán)境上使用。

下面是一個(gè)調(diào)試器的截圖:


image

Hava another debugger in ming? see Working with Debubbers

路由

現(xiàn)代的移動(dòng)應(yīng)用程序都有美觀的URL地址。這便于人們記憶,這對(duì)于使用較慢網(wǎng)絡(luò)連接的移動(dòng)設(shè)備的應(yīng)用來(lái)說(shuō)尤其如此。
如果用戶可以直接進(jìn)入所需的頁(yè)面,而不必打索引頁(yè)面,則更有可能他們會(huì)喜歡該頁(yè)面,并且下次再來(lái)。

就像你在上面看見(jiàn)的,路由裝飾器route()的作用就是把一個(gè)函數(shù)綁定到一個(gè)URL地址。
下面是一些基本的例子:

@app.route('/')
def index():
    return 'Index Page'
    
@app.route('/hello')
def hello():
    return 'Hello, World!'

當(dāng)然,不僅僅如此!您可以使URL的某些部分動(dòng)態(tài),并將多個(gè)規(guī)則附加到一個(gè)函數(shù)。

變量規(guī)則

向URL中添加變量,你可以這樣標(biāo)記 <variable_name> 。
這個(gè)部分會(huì)以關(guān)鍵字的形式出入到你的函數(shù)中,你也可以選擇使用類(lèi)型聲明 <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

有以下的類(lèi)型轉(zhuǎn)換:

|name    | descriptions                                   |
|:-------|-----------------------------------------------:|
|string  | accepts any text without a shash (the default) |
|int     | accepts integers                               |
|float   | like _int_ but for floating point values       |
|path    | like the default but also accepts slashes      |
|any     | mathches one of the items provided             |
|uuid    | accepts UUID strings                      |

特殊的URL/重定向行為

Flask的URL規(guī)則基于Werkzeug的路由模塊。他的這個(gè)模塊背后的想法是確?;贏pache和早期的HTTP服務(wù)器規(guī)定的先例的漂亮而唯一的URL。

看一下下面兩個(gè)規(guī)則:

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

雖然他們看起來(lái)很像,但是區(qū)別在于URL定義時(shí)使用的斜杠 / 。在第一個(gè)URL定義中,
projects地址的末尾有一個(gè) / 。這就類(lèi)似于文件系統(tǒng)中的一個(gè)文件夾。
當(dāng)你嘗把斜杠去掉的時(shí)候,它會(huì)重定向到帶斜杠的URL。

在第二個(gè)示例中,URL末尾是沒(méi)有斜杠的,而是像類(lèi)UNIX系統(tǒng)上的文件的路徑名。使用尾部斜杠訪問(wèn)該URL將產(chǎn)生404“未找到”錯(cuò)誤。

這種行為允許相對(duì)URL繼續(xù)工作,即使省略尾部斜線,與Apache和其他服務(wù)器的工作原理一致。
此外,URL將保持唯一,這有助于搜索引擎避免對(duì)同一頁(yè)面進(jìn)行兩次索引。

構(gòu)建URL

如果可以匹配URL,是否Flask也可以生成它們?回答是肯定的。你可以使用url_for()函數(shù)把一個(gè)URL綁定到特定的
視圖函數(shù)。它允許函數(shù)名作為第一個(gè)參數(shù),和其他的一些關(guān)鍵字參數(shù),每一個(gè)對(duì)應(yīng)于URL中的可變部分。
未知的變量部分作為查詢參數(shù)附加到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像處理請(qǐng)求一樣,
即使我們使用的是Python shell。請(qǐng)查看詳細(xì)描述Context Locals

為什么要使用URL構(gòu)建函數(shù) url_for() 來(lái)構(gòu)建URL,而不是將它們直接寫(xiě)到模板中?
這樣做有3個(gè)好處:

  1. Reversing通常比直接硬編碼更具有可讀性。更重要的是,它允許您一次更改URL,而無(wú)需記住所有需要更改URL。
  2. URL構(gòu)建將為您透明地處理特殊字符和Unicode數(shù)據(jù)的轉(zhuǎn)義,因此您不必處理它們。
  3. 如果您的應(yīng)用程序位于URL根目錄之外 - 例如,/myapplication 而不是 / , url_for() 將會(huì)很好的處理他們。

HTTP方法

HTTP(Web應(yīng)用程序直間進(jìn)行溝通的協(xié)議)知道用于訪問(wèn)URL的不同方法。默認(rèn)的,一個(gè)路由僅僅對(duì)GET請(qǐng)求進(jìn)行回應(yīng)。
但是你可以通過(guò)向route()裝飾器增加methods參數(shù)來(lái)改變。下面是一些示例:

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        do_the_login()
    else:
        show_the_login_form()

如果是GET請(qǐng)求,HEAD會(huì)自動(dòng)為你加上,你不用自己進(jìn)行處理。也會(huì)確保請(qǐng)求頭HEAD按照HTTP RFC(the document describing the HTTP protocol)
的要求進(jìn)行處理。和Flask0.6一樣,OPTIONS也會(huì)自動(dòng)為你實(shí)現(xiàn)。

你是不是不知道什么是HTTP方法???不必?fù)?dān)心,這里有一個(gè)HTTP方法的快速介紹,并且解釋為什么它們很重要:

GET

瀏覽器告訴服務(wù)器只需獲取存儲(chǔ)在該頁(yè)面上的信息并發(fā)送它。這可能是最常用的方法。

HEAD

瀏覽器告訴服務(wù)器獲取信息,但它只對(duì)頁(yè)眉感興趣,而不是頁(yè)面的內(nèi)容。一個(gè)應(yīng)用程序應(yīng)該可以處理這樣的請(qǐng)求,就像接到一個(gè)GET請(qǐng)求,
但是不返回實(shí)際的內(nèi)容。在Flask中,你一點(diǎn)兒也不需要為此擔(dān)心,底層的Werkzeug庫(kù)會(huì)為你做這些。

POST

瀏覽器告訴服務(wù)器,它想向URL中推送一些新的信息,并且服務(wù)器需要保證數(shù)據(jù)被保存了,而且只保存了一次。
這是一種HTML表單(forms)經(jīng)常向服務(wù)器傳送數(shù)據(jù)的方式。

PUT

POST相似,但服務(wù)器可能會(huì)多次觸發(fā)存儲(chǔ)過(guò)程來(lái)覆蓋舊值。也許你會(huì)疑問(wèn),為什么需要這個(gè)呢?但是這樣做確實(shí)有一些好處。
假如在傳輸數(shù)據(jù)的時(shí)候連接斷開(kāi)了,在這種情況下,瀏覽器和服務(wù)器之間的系統(tǒng)可能會(huì)第二次安全地接收請(qǐng)求,而不會(huì)破壞事件。
如果使用的是POST請(qǐng)求的話,就沒(méi)法實(shí)現(xiàn),因?yàn)橹粫?huì)被觸發(fā)一次。

DELETE

刪除在特定位置的信息。

OPTIONS

為客戶提供一個(gè)快速的方法來(lái)確定此URL支持哪些方法。從Flask 0.6開(kāi)始,這是為您自動(dòng)實(shí)現(xiàn)的。

靜態(tài)文件

動(dòng)態(tài)的互聯(lián)網(wǎng)應(yīng)用也需要靜態(tài)的文件。通常也是存儲(chǔ)CSS和JavaScript文件的地方。
理想情況下,您的Web服務(wù)器被配置為為您服務(wù),但在開(kāi)發(fā)期間,F(xiàn)lask也可以執(zhí)行此操作。
只需在程序包中或在模塊旁邊創(chuàng)建一個(gè)名為static的文件夾,它將在應(yīng)用程序的 /static 處可用。
如果為靜態(tài)文件創(chuàng)建一個(gè)URL地址,使用特殊的static端點(diǎn)名稱:

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

這個(gè)文件必須被保存在目錄static/style.css的文件系統(tǒng)下。

模板渲染

在Python中生成HTML不是很有趣的事情,實(shí)際上很麻煩,因?yàn)槟仨氉孕袌?zhí)行HTML轉(zhuǎn)義以保護(hù)應(yīng)用程序的安全。
鑒于此,F(xiàn)lask默認(rèn)使用Jinjia2模板引擎。

你可以使用render_template()方法渲染一個(gè)模板。你所需要做的僅僅是提供一個(gè)模板的名字以及想要傳入模板的一組變量名。
這組變量名是以字典的形式傳入的。下面是一個(gè)簡(jiǎn)單的示例,如何渲染模板:

from flask import render_template

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

Flask將會(huì)在templates文件夾內(nèi)尋找模板。所以,如果你的程序是一個(gè)模塊的話,該文件夾位于模塊的旁邊,
如果他是一個(gè)包的話,該文件夾位于包內(nèi)。

示例1:模塊

/application.py
/templates
    /hello.html

示例2:包

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

對(duì)于模板,你可以使用Jinjia2模板的全部功能。請(qǐng)到官網(wǎng)Jinjia2 Template Documentation
獲取更多信息。

下面是一個(gè)示例模板:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
    <h1>Hello {{name}}</h1>
{%else%}
    <h1>Hello, World!</h1>
{%endif%}

在模板內(nèi)部,你也可以使用request, sessiong對(duì)象,還有get_flashed_messages()函數(shù)。

在模板中使用繼承很重要,如果你想知道繼承是怎么工作的,請(qǐng)點(diǎn)擊Template Inheritance
文檔?;镜哪0謇^承可以使每一個(gè)頁(yè)面有相同的標(biāo)題、導(dǎo)航、頁(yè)腳。
模板具有自動(dòng)轉(zhuǎn)譯的功能,如果name內(nèi)板涵HTML內(nèi)容,那么它將會(huì)被自動(dòng)轉(zhuǎn)譯。如果你相信一個(gè)變量(例如因?yàn)樗鼇?lái)自將wiki標(biāo)記轉(zhuǎn)換為HTML的模塊),并且你知道它是安全的
HTML內(nèi)容,那么你可以使用Markup類(lèi)進(jìn)行標(biāo)記,或者你也可以在模板內(nèi)使用 |safe 過(guò)濾器。
請(qǐng)到Jinjia2文檔獲得更多信息。

下面簡(jiǎn)單介紹Markup類(lèi)如何工作的:

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的變化:所有模板不再啟用自動(dòng)轉(zhuǎn)譯。模板的以下擴(kuò)展名觸發(fā)自動(dòng)轉(zhuǎn)義:.html,.htm,.xml,.xhtml。從字符串加載的模板將禁用自動(dòng)轉(zhuǎn)義。

獲取請(qǐng)求數(shù)據(jù)

對(duì)于Web應(yīng)用程序,對(duì)客戶端發(fā)送到服務(wù)器的數(shù)據(jù)做出反應(yīng)至關(guān)重要。在Flask中,這些信息由全局變量request對(duì)象提供。
如果你對(duì)Python有了解,也許會(huì)有疑問(wèn),為什么它可以是全局的(因?yàn)镻ython沒(méi)有聲明的全局、局部變量),并且Flask怎么
保證的線程安全。答案書(shū)本地上下文環(huán)境(context locals):

本地上下文(context locals)

內(nèi)幕消息(Insider Information)

如果您想了解這些工作原理以及如何使用上下文本地實(shí)現(xiàn)測(cè)試,請(qǐng)閱讀本節(jié),否則只需跳過(guò)該部分。

在Flask內(nèi)有一些固定的全局對(duì)象,但是不是常規(guī)所說(shuō)的那樣的全局對(duì)象。
這些對(duì)象實(shí)際上是對(duì)特定上下文對(duì)象的哦代理。太拗口了?。。〉珜?shí)際上這很容易理解。

想象一下一個(gè)正在處理線程的上下文,這時(shí)一個(gè)新的請(qǐng)求進(jìn)來(lái)了,web服務(wù)器覺(jué)定新開(kāi)一個(gè)線程(或其他的方式,底層對(duì)象能夠處理除線程之外的并發(fā)系統(tǒng)),
當(dāng)Flask啟動(dòng)其內(nèi)部請(qǐng)求處理時(shí),它會(huì)找出當(dāng)前線程活動(dòng)的上下文,并將當(dāng)前應(yīng)用程序和WSGI環(huán)境綁定到該上下文(線程)。
它以一種智能的方式執(zhí)行,以便一個(gè)應(yīng)用程序可以調(diào)用另一個(gè)應(yīng)用程序而不會(huì)中斷。

所以,這對(duì)于你來(lái)說(shuō)意味著什么?基本上你完全可以忽視,除非你在做某些事情,如單元測(cè)試的時(shí)候。您將注意到,由于沒(méi)有請(qǐng)求對(duì)象,依賴于請(qǐng)求對(duì)象的代碼將突然中斷。
解決方案是自己創(chuàng)建一個(gè)請(qǐng)求對(duì)象并將其綁定到上下文。對(duì)于單元測(cè)試來(lái)說(shuō),最簡(jiǎn)單的方法是使用test_request_context()方法。
結(jié)合with語(yǔ)句,它將綁定一個(gè)測(cè)試請(qǐng)求,以便您可以與它進(jìn)行交互。下面是一個(gè)示例:

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'
    

另一種可能性是將整個(gè)WSGI環(huán)境傳遞給 request_context() 方法:

from flask import request
with app.request_context(environ):
    assert request.method == 'POST'

請(qǐng)求對(duì)象(Request Object)

請(qǐng)求對(duì)象在API部分中有講述,我們將不在此詳細(xì)介紹,參加request
這是一些最常見(jiàn)的操作的概述。首先,你需要從 flask 模塊中引入:

from flask import request, render_template

使用method屬性,可以獲取當(dāng)前的請(qǐng)求方法,你可以使用form屬性獲取表單數(shù)據(jù)(以 POSTPUT 請(qǐng)求發(fā)送的數(shù)據(jù))
以下是上述兩個(gè)屬性的完整示例:

from flask import request
@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 mentod
        # was GET or the credentials were invalid
        return render_template('login.html', error=error)

如果 form 屬性中沒(méi)有所尋找的關(guān)鍵字,將會(huì)發(fā)生什么?在這種情況下,會(huì)拋出一個(gè)KeyError錯(cuò)誤。
你可以像捕捉標(biāo)準(zhǔn)錯(cuò)誤一樣對(duì)它進(jìn)行捕獲,如果你沒(méi)有捕獲的話,則會(huì)出現(xiàn)一個(gè) HTTP404 錯(cuò)誤請(qǐng)求頁(yè)面。
所以在許多情況下,你不必處理這個(gè)問(wèn)題。

如果想獲取在UTL(?key=value)中提交的參數(shù),你可以使用args屬性:

from flask import request
searchword = request.args.get('key', '')

我們建議使用 get 方法獲取URL參數(shù),或者通過(guò)捕獲KeyError
為你用戶可能輸入錯(cuò)的URL,這時(shí)候,如果返回 400 的錯(cuò)誤請(qǐng)求頁(yè)面會(huì)顯得不友好。

如果想查看request對(duì)象的全部方法和屬性,請(qǐng)點(diǎn)擊request.

上傳文檔

使用Flask,你可以輕易的處理文件的上傳。請(qǐng)確保在你的HTML表單里設(shè)置 enctype='multipart/form-data' 屬性。
否則,瀏覽器不會(huì)發(fā)送你的文件滴。

待上傳的文件存儲(chǔ)在文件系統(tǒng)的內(nèi)存或臨時(shí)位置。你可以通過(guò)查看request對(duì)象里的files屬性,來(lái)獲得這些文件。
每一個(gè)待上傳的文件都是放在這個(gè)字典里。它就像一個(gè)標(biāo)準(zhǔn)的Python文件對(duì)象一樣,但它也有一個(gè) save() 方法,可以將該文件存儲(chǔ)在服務(wù)器的文件系統(tǒng)上。
下面是一個(gè)簡(jiǎn)單的示例,展示它是如何工作的:

from flask import request

@app.route('/upload', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/upload_file.txt')

如果您想知道文件在客戶端上傳到應(yīng)用程序之前如何命名,你可查看filename屬性。
但是,請(qǐng)記住,這個(gè)值是可以被偽造的,永遠(yuǎn)不會(huì)相信這個(gè)價(jià)值。如果要使用客戶端的文件名將文件存儲(chǔ)在服務(wù)器上,請(qǐng)使用
Werkzeug提供給你的secure_filemame()函數(shù),示例如下:

from flask import request
from werkzeug import secure_filename

@app.route('/upload', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))

想看更好的例子,請(qǐng)查閱Uploading Files

Cookies

可以使用cookies屬性獲取cookies。
可以使用response對(duì)象的[set_cookie]方法設(shè)置cookies。request對(duì)象的cookies屬性
是一個(gè)包含所有用戶傳遞的cookies的字典。如果你想使用sessions,,就不要直接使用cookies,請(qǐng)使用Flask提供的Sessions
在cookies的基礎(chǔ)上增加了安全性。

示例,讀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 cookies is missing.

示例,保存cookies:

from flask import make_response, render_template

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

請(qǐng)記住,是在response對(duì)象上設(shè)置cookies。因?yàn)槟阃ǔV皇菑囊晥D函數(shù)返回字符串,F(xiàn)lask將會(huì)將它們轉(zhuǎn)換為響應(yīng)對(duì)象。
如果您明確要這樣做,可以使用make_response函數(shù),然后修改它。

有時(shí)您可能想要在響應(yīng)對(duì)象不存在的位置設(shè)置一個(gè)cookie。這可以使用Defered Request Callbacks模式來(lái)實(shí)現(xiàn)。
這一部分請(qǐng)查閱About Response

重定向和錯(cuò)誤(Redirects and Errors)

要將用戶重定向到另一個(gè)端點(diǎn),請(qǐng)使用redirect函數(shù).
要使用錯(cuò)誤代碼提前中止請(qǐng)求,請(qǐng)使用abort函數(shù):

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

這是一個(gè)相當(dāng)無(wú)關(guān)的例子,因?yàn)橛脩魧⒈粡乃饕囟ㄏ虻綗o(wú)法訪問(wèn)的頁(yè)面(401意味著拒絕訪問(wèn)),僅僅展示如何使用。

默認(rèn)情況下,每個(gè)錯(cuò)誤代碼都會(huì)顯示黑白錯(cuò)誤頁(yè)面。如果你想自己設(shè)置錯(cuò)誤頁(yè)面,你可以使用errorhandler()裝飾器。

from flask import render_template

@app.route(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

請(qǐng)注意在函數(shù)render_template后面的 404 。
這告訴Flask該頁(yè)面的狀態(tài)代碼應(yīng)該是404,這意味著沒(méi)有找到。默認(rèn)情況下,200意味著:一切順利。

更多細(xì)節(jié),請(qǐng)查看Error handler.

關(guān)于響應(yīng)

視圖函數(shù)的返回值將自動(dòng)轉(zhuǎn)換為響應(yīng)對(duì)象。如果返回值是一個(gè)字符串,則將其轉(zhuǎn)換為響應(yīng)對(duì)象,其中字符串作為響應(yīng)體,
200 OK狀態(tài)代碼和text / html mimetype。Flask將返回值轉(zhuǎn)換為響應(yīng)對(duì)象所使用的的邏輯如下:

  1. 如果返回正確類(lèi)型的響應(yīng)對(duì)象,則從視圖直接返回。
  2. 如果它是一個(gè)字符串,則使用該數(shù)據(jù)和默認(rèn)參數(shù)創(chuàng)建一個(gè)響應(yīng)對(duì)象。
  3. 如果返回一個(gè)元組,元組中的項(xiàng)可以提供額外的信息。這樣的元組形式必須是(response, status, headers) or (response, headers),元組中必須至少有一個(gè)元素。
    狀態(tài)值將覆蓋狀態(tài)代碼,標(biāo)題可以是附加標(biāo)題值的列表或字典。
  4. 如果以上情況都沒(méi)有,則Flask將假定返回值是一個(gè)有效的WSGI應(yīng)用程序,并將其轉(zhuǎn)換為響應(yīng)對(duì)象。

如果您想要在視圖中獲取生成的響應(yīng)對(duì)象,你可以使用make_response函數(shù)。
假設(shè)你有下面這個(gè)視圖函數(shù):

@app.errorhandler(404)
def not_found(error):
    return render_template('error.html'), 404

您只需要使用make_response()包裝返回表達(dá)式,并獲取響應(yīng)對(duì)象進(jìn)行修改,然后返回:

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp

會(huì)話(sessions)

除了請(qǐng)求對(duì)象之外,還有一個(gè)名為session的第二個(gè)對(duì)象,它允許您將特定于用戶的信息從一個(gè)請(qǐng)求存儲(chǔ)到下一個(gè)請(qǐng)求。
這是在您的cookies之上實(shí)現(xiàn)的,并且用密碼標(biāo)識(shí)cookie。這意味著用戶可以查看您的cookie的內(nèi)容,但不修改它,除非他們知道用于簽名的密鑰。

為了使用會(huì)話,你必須設(shè)置一個(gè)密鑰。下面展示會(huì)話是如何工作的:

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=['POST', 'GET'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form 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()會(huì)為您轉(zhuǎn)義。

如何生成好的密鑰

隨機(jī)的問(wèn)題是很難判斷真正的隨機(jī)性。密鑰應(yīng)盡可能隨機(jī).您的操作系統(tǒng)有方法根據(jù)加密隨機(jī)生成器生成漂亮的隨機(jī)東西,可以用于獲取這樣的密鑰:

import os
os.urandom(24)

基于Cookie的會(huì)話的提示:Flask將會(huì)取得您放入會(huì)話對(duì)象的值并將其序列化,放入cookie。
如果您發(fā)現(xiàn)某些值不會(huì)在請(qǐng)求中持久存在,而你確實(shí)啟用了Cookie,并且您沒(méi)有收到明確的錯(cuò)誤消息,請(qǐng)檢查您的頁(yè)面響應(yīng)中的cookie大小與Web瀏覽器支持的大小相比。

除了默認(rèn)的基于客戶端的會(huì)話之外,如果要在服務(wù)器端處理會(huì)話,還有幾個(gè)Flask擴(kuò)展支持此功能。

消息閃爍(Message Flashing)

良好的應(yīng)用程序和用戶界面都是關(guān)于反饋的。如果用戶沒(méi)有得到足夠的反饋,他們可能會(huì)最終討厭應(yīng)用程序。Flask提供了一種非常簡(jiǎn)單的方法來(lái)向用戶提供閃爍系統(tǒng)的反饋。
消息閃爍使在請(qǐng)求結(jié)束時(shí)記錄一個(gè)消息,并在下一個(gè)(而且只有下一個(gè))請(qǐng)求中訪問(wèn)它變得簡(jiǎn)單。這通常與布局模板組合以展示消息。

使用flash()方法閃爍消息。
您可以使用get_flashed_messages()獲取消息,這個(gè)方法也可以在模板中使用。
查閱Message Flashing獲取更多示例。

Logging

New in version 0.3。

有時(shí)您可能處于這樣的情況下,你處理的數(shù)據(jù)應(yīng)該是正確的,但是實(shí)際上它是錯(cuò)誤的。
例如,您可能有一些客戶端代碼向服務(wù)器發(fā)送HTTP請(qǐng)求,但顯然格式錯(cuò)誤。這可能是由用戶篡改數(shù)據(jù)或客戶端代碼失敗引起的。
大多數(shù)情況下,在這種情況下可以回復(fù)400 Bad Request,但有時(shí)候不會(huì)這樣做,并且代碼必須繼續(xù)工作。

你可能還想記錄發(fā)生了什么事情。這是loggers派上用場(chǎng)的地方。
Flask 0.3版本,預(yù)先配置了一個(gè)logger供您使用。下面是一些示例:

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('A error occurred')

這個(gè)logger是一個(gè)標(biāo)準(zhǔn)的loggingLogger,
請(qǐng)前往logging documentation獲取更多信息。
更多Application Errors

Hooking in WSGI Middlewares

如果要向應(yīng)用程序添加WSGI中間件,則可以包裝內(nèi)部WSGI應(yīng)用程序。
例如,如果要使用Werkzeug軟件包中的一個(gè)中間件來(lái)處理lighttpd中的錯(cuò)誤,可以這樣做:

from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)

使用Flask擴(kuò)展

擴(kuò)展是幫助您完成常見(jiàn)任務(wù)的軟件包。例如,F(xiàn)lask-SQLAlchemy提供SQLAlchemy支持,使其易于與Flask一起使用。
更多Flask擴(kuò)展,請(qǐng)查看Flask Extensions

部署到Web服務(wù)器

準(zhǔn)備好部署你的新Flask應(yīng)用了嗎?參加Deployment Options.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,530評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,407評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,981評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,759評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,204評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,415評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,955評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,650評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,892評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,675評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容