Flask Markup 上下文,request


在模板渲染中,使用Markup轉換變量中的特殊字符

from flask import Markup

Markup函數對字符串進行轉移處理再傳遞給render_template()函數

在瀏覽器中顯示標簽代碼

路由地址的反響生成

通過函數名獲得與其綁定的Url地址

需要使用url_for函數進行反向解析

with app.text_request_context()
    print(url_for('f_root')) # 輸出:/
app.text_request_context()方法告訴解釋器為在其作用域中的代碼模擬一個HTTP請求上下文,使其好像被一個HTTP請求所調用

使用Context上下文
他是服務器端獲得應用及請求相關信息的對象
1、會話上下文
會話(session)是一種客戶端與服務器端保持狀態的解決方案,會話上下文是用來實現這種解決方案的存儲結構
from flask import Flask,session
from datetime import datetime

app = Flask(__name__)

app.secret_key = 'SET_ME_BEFORE_USE_SESSION'


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

@app.route('/write_session')
def wirteSession():
    session['key_time']=datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 將當前時間保存在Session中
    return session['key_time'] # 返回當前時間
@app.route('/read_session')
def readSession():
    return session.get('key_time')# 獲取上次調用wirteSession時寫入的時間並返回

除了正常的數據保存和讀取,flask.session對象還維護自身的狀態,通過

new 判斷本次請求的Session是否時新建的

modified 判斷本次請求中是否修改過Session鍵值

@app.route('/write_session')
def wirteSession():
    session['key_time']=time.time() # 將當前時間保存在Session中
    return session.modified # 因為之前進行了Session設置,所以判斷本次請求是否被修改過(modified)返回TRUE

應用全局對象

from flask import Flask,g

class MYDB():
    def __init__(self):
        print('一個數據庫鏈接已經建立')

    def close(self):
        print('數據庫已經關閉')

def connect_to_database():
    return MYDB()

def get_db():
    db = getattr(g,'_database',None)
    if db is None:
        db = connect_to_database()
        g._database = db # 存入Flask.g對象中
    return db

@app.teardown_request # 在請求結束時自動被Flask框架調用
def teardown_db(response):
    db = getattr(g,'_database',None)# 從Flask.g對象中獲取對象,檢查是否有鏈接數據庫對象,如果有則關閉
    if db is not None:
        db.close()
可以在請求處理函數的任何地方調用get_db()
class MYDB():
    def __init__(self):
        print('一個數據庫鏈接已經建立')

    def close(self):
        print('數據庫已經關閉')

def connect_to_database():
    return MYDB()

def get_db():
    db = getattr(g,'_database',None)
    if db is None:
        db = connect_to_database()
        g._database = db # 存入Flask.g對象中
    return db

@app.teardown_request
def teardown_db(response):
    db = getattr(g,'_database',None)# 從Flask.g對象中獲取對象
    if db is not None:
        db.close()
def login():
    db=get_db()  # 第一次調用getdb  創建數據庫鏈接
    session['has_login']=True
    # 使用db檢查數據庫中的用戶名和密碼
def view_list():
    if 'has_login' not in session:
        login()
    db = get_db() # 第二次調用get_db()# 直接復用之前建立的鏈接
    # 使用db 從數據庫查詢數據,返回teardown_db()將會被自動調用

請求上下文生命周期

from flask import Flask, g, request
 
app = Flask(__name__)
 
@app.before_request
def before_request():
    print 'before request started'
    print request.url
 
@app.before_request
def before_request2():
    print 'before request started 2'
    print request.url
    g.name="SampleApp"
 
@app.after_request
def after_request(response):
    print 'after request finished'
    print request.url
    response.headers['key'] = 'value'
    return response
 
@app.teardown_request
def teardown_request(exception):
    print 'teardown request'
    print request.url
 
@app.route('/')
def index():
    return 'Hello, %s!' % g.name
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

訪問”http://localhost:5000/”后,會在控制台輸出:

before request started
http://localhost:5000/
before request started 2
http://localhost:5000/
after request finished
http://localhost:5000/
teardown request
http://localhost:5000/

request對象只有在請求上下文的生命周期內才可以訪問。離開了請求的生命周期,其上下文環境也就不存在了,自然也無法獲取request對象。而上面介紹的幾個由上下文裝飾器修飾的Hook函數,會掛載在請求生命周期內的不同階段,所以其內部可以訪問request對象。

構建請求上下文環境

我們使用Flask的內部方法”request_context()”來構建一個客戶端請求上下文。

from werkzeug.test import EnvironBuilder
 
ctx = app.request_context(EnvironBuilder('/','http://localhost/').get_environ())
ctx.push()
try:
    print request.url
finally:
    ctx.pop()

“request_context()”會創建一個請求上下文”RequestContext”類型的對象,其需接收”werkzeug”中的”environ”對象為參數。”werkzeug”是Flask所依賴的WSGI函數庫

我們可以在客戶端的請求之外訪問request對象,其實此時的request對象即是剛創建的請求上下文中的一個屬性”request == ctx.request”。啟動Flask時,控制台仍然可以打印出訪問地址”http://localhost/”。上面的代碼可以用with語句來簡化:

from werkzeug.test import EnvironBuilder
 
with app.request_context(EnvironBuilder('/','http://localhost/').get_environ()):
    print request.url

請求上下文的實現方式

對於Flask Web應用來說,每個請求就是一個獨立的線程。請求之間的信息要完全隔離,避免沖突,這就需要使用本地線程環境(ThreadLocal),

”ctx.push()”方法,會將當前請求上下文,壓入”flask._request_ctx_stack”的棧中,同時這個”_request_ctx_stack”棧是個ThreadLocal對象,也就是”flask._request_ctx_stack”看似全局對象,其實每個線程的都不一樣。請求上下文壓入棧后,再次訪問其都會從這個棧的頂端通過”_request_ctx_stack.top”來獲取,所以取到的永遠是只屬於本線程中的對象,這樣不同請求之間的上下文就做到了完全隔離。請求結束后,線程退出,ThreadLocal線程本地變量也隨即銷毀,”ctx.pop()”用來將請求上下文從棧里彈出,避免內存無法回收。

——————————————————————————————————————————————————————————————————————

主要是在服務端獲得從客戶端提交的數據,包括url參數,表單數據,cookies等

from flask import Flask,request,url_for,redirect

app = Flask(__name__)

@app.route('/redirect_url')
def redirect_url():
    next = request.args.get('next') or url_for('index')
    return redirect(next)

@app.route('/echo_url')
def echo_url():
    return request.base_url

自定義上下文變量和函數

自定義變量

from flask import current_app
 
@app.context_processor
def appinfo():
    return dict(appname=current_app.name)

函數返回的是一個字典,里面有一個屬性”appname”,值為當前應用的名稱。我們曾經介紹過,這里的”current_app”對象是一個定義在應用上下文中的代理。函數用”@app.context_processor”裝飾器修飾,它是一個上下文處理器,它的作用是在模板被渲染前運行其所修飾的函數,並將函數返回的字典導入到模板上下文環境中,與模板上下文合並。然后,在模板中”appname”成為了可訪問的上下文對象。我們可以在模板中將其輸出:

  <p>Current App is: {{ appname }}</p>

自定義函數

同理我們可以自定義上下文函數,只需將上例中返回字典的屬性指向一個函數即可,下面我們就來定義一個上下文函數來獲取系統當前時間:

import time
 
@app.context_processor
def get_current_time():
    def get_time(timeFormat="%b %d, %Y - %H:%M:%S"):
        return time.strftime(timeFormat)
    return dict(current_time=get_time)
  <p>Current Time is: {{ current_time() }}</p>
  <p>Current Day is: {{ current_time("%Y-%m-%d") }}</p>

 

應用上下文環境

current_app代理

from flask import Flask, current_app
 
app = Flask('SampleApp')
 
@app.route('/')
def index():
    return 'Hello, %s!' % current_app.name

我們可以通過”current_app.name”來獲取當前應用的名稱,也就是”SampleApp”。”current_app”是一個本地代理,它的類型是”werkzeug.local. LocalProxy”,它所代理的即是我們的app對象,也就是說”current_app == LocalProxy(app)”。使用”current_app”是因為它也是一個ThreadLocal變量,對它的改動不會影響到其他線程。你可以通過”current_app._get_current_object()”方法來獲取app對象。

既然是ThreadLocal對象,那它就只在請求線程內存在,它的生命周期就是在應用上下文里。離開了應用上下文,”current_app”一樣無法使用

構建應用上下文環境

同請求上下文一樣,我們也可以手動構建應用上下文環境:

with app.app_context():
    print current_app.name

“app_context()”方法會創建一個”AppContext”類型對象,即應用上下文對象,此后我們就可以在應用上下文中,訪問”current_app”對象了。

應用上下文Hook函數

應用上下文也提供了裝飾器來修飾Hook函數,不過只有一個”@app.teardown_appcontext”。它會在應用上下文生命周期結束前,也就是從”_app_ctx_stack”出棧時被調用。我們可以加入下面的代碼,順便也驗證下,是否應用上下文在每個請求結束時會被銷毀。

@app.teardown_appcontext
def teardown_db(exception):
    print 'teardown application'

 

request的屬性

下面是request可使用的屬性,其中黑體是比較常用的。

  • form 
    一個從POST和PUT請求解析的 MultiDict(一鍵多值字典)。

  • args 
    MultiDict,要操作 URL (如 ?key=value )中提交的參數可以使用 args 屬性:

searchword = request.args.get('key', '')
  • values 
    CombinedMultiDict,內容是formargs。 
    可以使用values替代form和args。

  • cookies 
    顧名思義,請求的cookies,類型是dict。

  • stream 
    在可知的mimetype下,如果進來的表單數據無法解碼,會沒有任何改動的保存到這個·stream·以供使用。很多時候,當請求的數據轉換為string時,使用data是最好的方式。這個stream只返回數據一次。

  • headers 
    請求頭,字典類型。

  • data 
    包含了請求的數據,並轉換為字符串,除非是一個Flask無法處理的mimetype。

  • files 
    MultiDict,帶有通過POST或PUT請求上傳的文件。

  • environ 
    WSGI隱含的環境配置。

  • method 
    請求方法,比如POST、GET。

  • path

  • script_root
  • url
  • base_url
  • url_root 
    如果用戶請求如下URL: 
    http://www.example.com/myapplication/page.html?x=y 
    以上的參數內容如下:
名稱 內容
path /page.html
script_root /myapplication
base_url http://www.example.com/myapplication/page.html
url http://www.example.com/myapplication/page.html?x=y
url_root http://www.example.com/myapplication/
    • is_xhr 
      如果請求是一個來自JavaScript XMLHttpRequest的觸發,則返回True,這個只工作在支持X-Requested-With頭的庫並且設置了XMLHttpRequest

    • blurprint 
      藍本名字。

    • endpoint 
      endpoint匹配請求,這個與view_args相結合,可是用於重構相同或修改URL。當匹配的時候發生異常,會返回None。

    • get_json(force=False, silent=False, cache=True)

    • json 
      如果mimetypeapplication/json,這個參數將會解析JSON數據,如果不是則返回None。 
      可以使用這個替代get_json()方法。

    • max_content_length 
      只讀,返回MAX_CONTENT_LENGTH的配置鍵。

    • module 
      如果請求是發送到一個實際的模塊,則該參數返回當前模塊的名稱。這是棄用的功能,使用blueprints替代。

    • on_json_loading_failed(e)
    • routing_exception = None 
      如果匹配URL失敗,這個異常將會/已經拋出作為請求處理的一部分。這通常用於NotFound異常或類似的情況。

    • url_rule = None 
      內部規則匹配請求的URL。這可用於在URL之前/之后檢查方法是否允許(request.url_rule.methods) 等等。 
      默認情況下,在處理請求函數中寫下 
      print('request.url_rule.methods', request.url_rule.methods) 
      會打印:

      request.url_rule.methods {‘GET’, ‘OPTIONS’, ‘HEAD’}

    • view_args = None 
      一個匹配請求的view參數的字典,當匹配的時候發生異常,會返回None。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM