Flask自帶的常用組件介紹
Flask的優點是靈活小巧,三行代碼即可運行一個web服務器,但基於Flask構建的功能並不比Django弱,關鍵就就是除了flask自帶的基礎功能外,還有豐富的組件進行支持,本文先對常用的自帶組件進行簡單的介紹。測試的Flask版本是0.12。
Flask自帶組件
在構建Flask應用導入的時候,通常是from flask import Flask
的方式開始的,說明flask這個python package裏面應該還藏了不少好東西,從源碼來看看:
from werkzeug.exceptions import abort from werkzeug.utils import redirect from jinja2 import Markup, escape from .app import Flask, Request, Response from .config import Config from .helpers import url_for, flash, send_file, send_from_directory, get_flashed_messages, get_template_attribute, make_response, safe_join, stream_with_context from .globals import current_app, g, request, session, _request_ctx_stack, _app_ctx_stack from .ctx import has_request_context, has_app_context, after_this_request, copy_current_request_context from .blueprints import Blueprint from .templating import render_template, render_template_string # the signals from .signals import signals_available, template_rendered, request_started, request_finished, got_request_exception, request_tearing_down, appcontext_tearing_down, appcontext_pushed, appcontext_popped, message_flashed, before_render_template # We‘re not exposing the actual json module but a convenient wrapper around # it. from . import json # This was the only thing that Flask used to export at one point and it had # a more generic name. jsonify = json.jsonify # backwards compat, goes away in 1.0 from .sessions import SecureCookieSession as Session json_available = True
Flask自帶組件基本上都在這裏了,我們一一來分析這些組件的功能及基本的用法。
- Flask
Flask應用的主類,在源碼分析中提到,不再贅述。這裏給一個Flask應用的經典樣例,請務必註意下面的代碼都是在此樣例基礎上進行拓展的。
#示例-1
from flask import Flask
app = Flask(__name__)
@app.route(‘/‘)
def hello_world():
return ‘Hello World!‘
if __name__ == ‘__main__‘:
app.run()
- render_template:
def render_template(template_name_or_list, **context)
template_name_or_list參數是模板名稱,context參數接受模板中已經定義的變量值。
Jinja是Flask的模板引擎,提供對HTML頁面的數據渲染,render_template是Flask中調用template目錄的html模板並渲染數據。代碼示例:
#示例-2
from flask import render_template
@app.route("/")
def index():
name="He Kejun"
return render_template("index.html",name=name)
上述的代碼中調用了/template/index.html
Hello, {{name}}
的方式顯示‘Hello, He Kejun‘
- session
flask的session機制,Flask從服務器通過瀏覽器的cookie保存信息,該信息通過應用的秘鑰進行加密確保數據安全。session在用戶身份認證和數據共享提供較好的幫助。樣例:
#示例-3
from flask import session
app.config["SECRET_KEY"]="YOU CAN NOT GUESS ME" #加密的秘鑰,建議放在配置文件中
@app.route("/")
def index():
session["name"]="kejun"
return "hello,world"
@app.route("/name")
def name():
return session["name"]
首先訪問http://127.0.0.1:5000 生成用戶名,查看瀏覽器的cookie可以看到session已經寫入了,這時候再訪問http://127.0.0.1:5000/name就可以看到名字了,在兩個HTTP請求之間共享了{name: kejun}
這個數據。
- url_for
def url_for(endpoint, **values):
根據已經定義好的view函數來創建URL到指定的endpoint,Flask的endpoint可以理解為Restful框架中資源。輸入的endpoint是函數名,values是關鍵字參數,每個關鍵字參數對應URL規則的變量部分,未知變量部分被插入到URL中作查詢參數,具體的樣例,我使用了官網的樣例
#示例-4
from flask import url_for
@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")) #/login
print(url_for("login",next="/")) #/login?next=/
print(url_for("profile,username="kejun")) @/user/kejun
- redirect
def redirect(location, code=302, Response=None):
參數location是跳轉的目標位置,code是HTTP響應碼默認是302(臨時移動),也可以設置為301(永久移動,即所請求的文檔在別處),303(參見其他信息),305(使用代理),不可以是300(多重選擇),304(未修正更新)。
redirect的作用是重定向,設置響應並跳轉到指定的位置。在Flask中通常與url_for這個功能一起使用。應用實例:
#示例-5
from flask import redirect
@app.route("/")
@app.route("/index")
def index():
return redirect(url_for("blog"))
@app.route("/blog")
def blog(): pass
在示例-5中,我們可以將一些用戶可能會訪問的鏈接重定向到博客主頁上。
- flash
def flash(message, category=‘message‘):
參數message是消息內容,category是消息類型,方便前端過濾。
Web設計中提供用戶的友好性是及時將反饋提供給用戶。消息閃現Flash提供了一個非常簡單的機制。
#示例-6-1
from flask import flash
def print_message():
flash("This is a message","message")
return "Message Page"
def print_error()
flash("This is a error","error")
return "Error Page"
在前端,我們可以這樣定義HTML頁面從而顯示內容
#示例-6-2
{% with msgs = get_flashed_messages(category_filter=["message"]) %}
{% if msgs %}
{% for msg in msgs %}
<p>{{msg}}</p>
{% endfor %}
{% endif %}
{% endwith %}
{% with errors= get_flashed_messages(category_filter=["error"]) %}
{% iferrors%}
{% for errorinerrors%}
<p>{{error}}</p>
{% endfor %}
{% endif %}
{% endwith %}
- make_response
def make_response(*args):
Flask會自動將view函數返回的轉換成響應對象,除此之外,你可以通過調用make_response
#示例-7
from flask import make_response
def index():
return render_template(‘index.html‘, foo=42)
def index():
response = make_response(render_template(‘index.html‘, foo=42))
resp.set_cookie("am_i_handsome","yes") #設置cookie
return response
在上述的示例中,通過make_response,還可以定制cookie。也就是說,通過make_response你可以個性化定制返回的響應對象。
- jsonify
對於數據進行json轉化,應用於通過ajax方式訪問時需要返回json數據。
#示例-8
from flask importjsonify
@app.route("/update_user_name",methods=[‘GET‘, ‘POST‘])
def update_user_name():
ip=request.headers.get(‘X-Real-Ip‘, request.remote_addr)
user_name=request.args.get(‘new_user_name‘,"",type=str)
if user_name:
if set_user_name(ip,user_name):
return jsonify(return_code="1")
return jsonify(return_code="0")
- blueprint
blueprint藍圖是flask自帶的一種拓展已有應用結構的方式,這是Flask在中大型Web應用中的一種框架設計。藍圖把把功能類似或者同一模塊下的視圖函數組合在一起,基於藍圖,我們可以把Flask應用拆分成不同的組件。每個藍圖都可以自定義自己的模板文件目錄和靜態目錄。定義好的藍圖目錄可以通過註冊的方式加入Flask應用中。代碼示例如下:
#示例-9-1
from flask import Blueprint
example=Blueprint(‘example‘,__name__,template_folder=‘templates/example‘,static_folder=‘static/example‘,url_prefix=‘/example‘)
#藍圖example下的視圖函數
@example.route
def index():
return render_template("index.html")
一個藍圖就是一個模塊,上述的example藍圖創建好後,需要註冊到Flask應用中,樣例代碼如下:
示例-9-2
from flask import Flask
from yourapplication.examples import example
app = Flask(__name__)
app.register_blueprint(example)
本文之前介紹了url_for的使用方法,在藍圖中使用url_for定位視圖函數需要增加藍圖名稱,如定位到上述index視圖函數url_for(‘example.index‘)
- request
Flask構建了一個與請求相關的全局變量,在所有的視圖函數及模板中都可以訪問該對象。應用示例如下:
#示例-10
from flask import request
def get_user_ip():
ip=request.headers.get(‘X-Real-Ip‘, request.remote_addr)
return "Request ip address is {0}".format(ip)
- abort
abort是Flask中Abort類的一個實例,通常采用abort(error_code)
的方式進行調用。abort的狀態碼最好是自己實現的錯誤定義,如示例-11所示。 - g
Flask中的全局變量g,可以為特定請求臨時存儲任何需要的數據並且是線程安全的,當請求結束時,這個對象會被銷毀,下一個新的請求到來時又會產升一個新的g。
#示例-11
from flask import g,session,abort,render_template
@app.before_request
def before_request():
if ‘user_name‘ in session:
g.user=User.query.get(session[‘user_name‘])
@app.route(‘/admin‘)
def admin():
if g.user is None:
abort(404)
return render_template(‘admin.html‘)
@app.errorhandler(404):
def page_not_found():
return render_template("404.html"),404
- send_from_directory
def send_from_directory(directory, filename, **options):
參數directory是文件所在目錄,filename是文件名稱,options參數是send_file的傳入參數,options可選的參數包括 mimetype、as_attachment、attachment_filename、add_etags、cache_timeout、conditional。
send_from_directory可以認為send_file上加了一層殼子,判斷了文件路徑及文件名,然後交由send_file處理,實際上將文件內容發給瀏覽器,所以它一個重要的應用場景是支持文件下載。
對於文件下載,媒體數據流傳輸的可以再研究一下send_file
和stream_with_context
這兩個功能,也非常好用。
示例代碼為:
#示例-11
from flask import send_from_directory
@app.route(‘/getfile‘, methods=[‘GET‘])
def download_file():
return send_from_directory(r"D:\Workspace\flask_source", "aa.txt", as_attachment=True)
- Markup
class Markup(text_type):
將輸入文本text_type標記為安全,不需要進行轉移。
如果將HTML作為變量通過Jinjia模板的方式作為變量插入頁面中,Flask會自動嘗試對HTML進行轉義。這是必要的安全措施,確保惡意用戶通過提交一段惡意代碼並顯示在頁面中,從而讓其他用戶的瀏覽器進行執行。Flask同時提供兩種方法來對安全的HTML不轉義直接顯示:一個是利用Markup類,二是利用Jinjia關鍵字safe
。示例代碼為:
示例-12
from flask import Markup
@app.route("/")
def index():
return Markup(‘Hello %s!‘) % ‘<strong>kejun</strong>‘#顯示strong標簽
@app.route("/1")
def index1():
return ‘Hello %s!‘ % ‘<strong>kejun</strong>‘#將strong標簽轉移成顯示
- current_app
應用上下文對象,官方文檔有詳細的介紹,
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
Flask自帶的常用組件介紹