flask-quickstart 官方網站翻譯

翻譯的網站
備注 我只會翻譯一些關鍵點。太簡單的就不翻譯了

Quickstart

一個小程序可能看起來會是這樣的

#hello.py
from flask import Flask
app = Flask(__name__)

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

通過命令行啟動程序有兩種方式

# 1.
export FLASK_APP=hello.py
flask run
#2.
export FLASK_APP=hello.py
python -m flask run

如果想讓你的程序成為可訪問的公共服務器

flask run --host=0.0.0.0

如果啟動成功你就可以通過 http://127.0.0.1:5000來看到你的Hello, World!

失敗的原因可能有多種,有可能是你的flask版本過低,也有可能導入的包名無效,或者你也可以開啟Debug模式

export FLASK_DEBUG=1

在這種模式下,flask能夠提供有用的調試信息,也能夠自動監聽代碼改動而重啟服務器。
另外,不建議你在開發階段,通過在代碼中使用如下方法啟動服務器。

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

flask 匹配與生成url的兩個函數

@app.route('/user/<username>')
... def profile(username): pass
url_for('profile',username='john deo')

Http(超文本協議) 傳輸方法

from flask import request

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

http PUT

PUT與POST類似,但服務器能通過覆蓋舊值多次激發存儲程序,例如傳輸過程種程序與服務器斷開連接,PUT能夠在不中斷服務的情況下安全的接受二次請求,而POST做不到。

靜態資源

包括css js 圖片等,flask都會默認在static文件中尋找它們。所以你要使用靜態文件,首先要建立static文件夾。

獲得靜態文件的地址可以通過

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

Html模版

默認的flask從template文件夾中尋找模版,確保它在你的模塊或包中
flask 封裝了jinja2模版引擎,模版中你仍然可以使用 request, session and g [1] 這些對象以及像 get_flashed_messages() 函數.
如果你想了解更多模版繼承的東西,可以查看 Template Inheritance ,它使得可以把像header, navigation and footer的東西放在一個頁面中。

flask可以自動忽略過濾變量中的html標記,所以如果你信任它,可以通過 Markup或者|safe 過濾器標簽來標記它是安全的不用過濾

>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'

現在自動過濾并不對全部模版適用了,自動過濾只對后綴為.html, .htm, .xml, .xhtml. 的文件適用。

請求數據?

flask提供了全局對象request來解決客戶端到服務器的數據處理反應。你可能會對flask如何將它變為全局可用且維持它的線程安全。答案就是上下文變量。

flask 能夠確保你在多線程環境中,獲得活動線程正確的數據

Context Locals 上下文變量

如果你想理解它是如何工作的,并且測試一下,那么可以讀一下接下來的部分。

flask中的全局對象和我們通常意義上的不同,它們只是某些特定上下文環境中的菊部變量的代理。

想象一個上下文環境,它是一個正在處理請求的線程。這時又來了一個請求,web服務器決定開辟一個新的線程(或者采用協程的方式),當flask開始進行內部處理這個請求的時候,flask計算出當前線程是活動的上下文環境,并且把當前的應用程序與wsgi環境同這個線程綁定起來。它通過一種智能的方式完成程序在不中斷情況下的協同工作。

wow 這對你意味著什么,意味著你可以不用操心當前處于什么上下文環境而放心的使用全局變量。當然如果你要做一些單元測試,那就行不通了。這時猴你發現代碼中以來的request對象沒有了,解決方法就是你自己創建一個并和上下文綁定。最簡單的方法是使用test_request_context() context manager這個上下文管理器,通過使用with語句綁定一個test request,然后你就可以使用它了。

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

from flask import request

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

Request 對象

表單數據

關于 request的詳細解釋,可以在這找到。我們接下來只進行常用方法的概述。
首先你要從flask模塊中導入它

from flask import request

最常用的請求方法是通過method屬性

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

通過request.form來獲取表單數據,如果沒有這個屬性,則拋出 KeyError,你可以自己捕獲它,或者讓他自動使用HTTP 400 錯誤頁面。

獲取URL中的查詢字符串,可以采用

searchword = request.args.get('key', '')

文件上傳

只要你在你的表單頭中設置了

enctype="multipart/form-data"

flask可以輕松處理你上傳的文件。上傳的文件被存儲在內存或臨時文件系統中,你能夠通過request的files屬性獲取它。所有上傳的文件都被存在這個屬性字典中,它就像標準的python文件,并且能夠讓你通過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屬性,你能夠獲得客戶端上傳文件的文件名,但它能夠被輕易偽造,所以更安全但方法是通過 secure_filename()方法。

from flask import request
from werkzeug.utils 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))
    ...

更多例子,點擊 Uploading Files.

Cookies

你可以通過cookies屬性來獲取cookies,通過response對象的set_cookie 方法來設置cookie

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.
from flask import make_response

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

注意到cookies是設置在response對象上的,當你從視圖函數中返回字符串,Flask會轉化成reponse對象,你也可以通過 make_response()函數明確的來返回它,并且修飾它。
('有時候需要在返回的時候設置headers,這時候你就需要make_respone函數來明確返回一個response object')
有時候你想要在response對象還不存在的時候創建cookie,你就需要利用 Deferred Request Callbacks 模式。
Deferred Request Callbacks最重要的關鍵點是before_request與after_request函數,這兩個函數分別是注冊一個函數在request之前和之后執行。before_request被注冊的函數沒有參數,after_request注冊的函數有一個參數 response_class的實例,并且返回一個response 對象。

from flask import g
#自定義裝飾器,通過g來傳遞數據
def after_this_request(f):
    if not hasattr(g, 'after_request_callbacks'):
        g.after_request_callbacks = []
    g.after_request_callbacks.append(f)
    return f

from flask import request
#在處理request前執行,如果沒有錯誤,進入視圖函數執行
@app.before_request
def detect_user_language():
    language = request.cookies.get('user_lang')
    if language is None:
        language = guess_language_from_request()
        @after_this_request #自定義裝飾器,將下面的函數放入g對象屬性中,此時response不存在
        def remember_language(response):
            response.set_cookie('user_lang', language)
    g.language = language

#request在視圖函數處理返回response后執行
@app.after_request
def call_after_request_callbacks(response):
    for callback in getattr(g, 'after_request_callbacks', ()):
        callback(response)
    return response

Redirects and Errors 重定向與錯誤

記住redirect 與 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()

默認的flask提供一套簡單的error page,如果想自定義,使用 errorhandler() 裝飾器:

from flask import render_template

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

調用 render_template() 后的404告訴 Flask頁面沒找到,默認是200,表示一切都好。

關于Responses

flask將返回值轉化為response對象的邏輯規則如下:
1、如果返回正確類型的response對象,視圖函數直接返回。
2、如果返回的是字符串,flask將string與一些默認參數轉化為response對象。
3、如果是一個元組,那么必須以(response, status, headers) 或 (response, headers)的形式出現,至少有一項必須存在。status value 將會覆蓋status,headers可以以列表或字典的形式出現。

如果你想在視圖中控制返回對象,使用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

Sessions

除request對象外還有一個session對象。session對象能夠讓你在request之間保存一些對用戶來說具體的信息。它是基于cookie的,并為其加密。也就是說它只能夠讀,但不能夠修改,除非你知道了密碼。

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

app = Flask(__name__)

@app.route('/')
def index():
    if 'username' in session:
     #Convert the characters &, <, >, ‘, and ” in string s to HTML-safe sequences
        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 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'

How to generate good secret keys?
如何產生好用的秘鑰

import os
os.urandom(24)

flask 默認的是客戶端session,如果你想處理服務端的,可以使用flask擴展解決。

Message Flashing

flask提供應用程序與用戶之間良好交互的方法。它在一個請求結束后記錄message,在下一個(僅下一個)請求中獲得它。
flash 例子 更多細節 Message Flashing

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

app = Flask(__name__)
app.secret_key = 'some_secret'

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

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

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

Logging

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

logger 是一個標準的logging Logger,可查看官方的 logging documentation獲得更多信息。

WSGI 中間件

不了解wsgi的可看一下我的另一篇文章帶你快速了解WSGI

(middleware需要把自己偽裝成一個服務器,接受應用程序,調用它,同時middleware還需要把自己偽裝成一個應用程序,傳給服務器程序。)
如果你想在你的程序中增加一個wsgi中間件,你可以包裝內部的wsgi應用程序。你可以像下面這樣做來使用LighttpdCGIRootFix中間件。

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

Flask 擴展

擴展都在這里

網站發布

看這里

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

推薦閱讀更多精彩內容