Flask 數(shù)據(jù)流

2021-08-11 10:33 更新

有時(shí),您希望發(fā)送非常巨量的數(shù)據(jù)到客戶端,遠(yuǎn)遠(yuǎn)超過您可以保存在內(nèi)存中的量。 在您實(shí)時(shí)地產(chǎn)生這些數(shù)據(jù)時(shí),如何才能直接把他發(fā)送給客戶端,而不需要在文件 系統(tǒng)中中轉(zhuǎn)呢?

答案是生成器和 Direct Response。

基本使用

下面是一個(gè)簡單的視圖函數(shù),這一視圖函數(shù)實(shí)時(shí)生成大量的 CSV 數(shù)據(jù), 這一技巧使用了一個(gè)內(nèi)部函數(shù),這一函數(shù)使用生成器來生成數(shù)據(jù),并且 稍后激發(fā)這個(gè)生成器函數(shù)時(shí),把返回值傳遞給一個(gè) response 對象:

from flask import Response

@app.route('/large.csv')
def generate_large_csv():
    def generate():
        for row in iter_all_rows():
            yield ','.join(row) + '\n'
    return Response(generate(), mimetype='text/csv')

每一個(gè) yield 表達(dá)式直接被發(fā)送給瀏覽器?,F(xiàn)在,仍然有一些 WSGI 中間件可能 打斷數(shù)據(jù)流,所以在這里請注意那些在帶緩存快照的調(diào)試環(huán)境,以及其他一些您可能 激活了的東西。

在模板中生成流

Jinja2 模板引擎同樣支持分塊逐個(gè)渲染模板。Flask 沒有直接暴露這一功能到 模板中,因?yàn)樗苌俦挥玫?,但是您可以很輕易的自己實(shí)現(xiàn):

from flask import Response

def stream_template(template_name, **context):
    app.update_template_context(context)
    t = app.jinja_env.get_template(template_name)
    rv = t.stream(context)
    rv.enable_buffering(5)
    return rv

@app.route('/my-large-page.html')
def render_large_template():
    rows = iter_all_rows()
    return Response(stream_template('the_template.html', rows=rows))

這一技巧是從應(yīng)用程序上的 Jinja2 的環(huán)境中得到那個(gè)模板對象,然后調(diào)用 stream() 函數(shù)而不是 render() 函數(shù)。前者返回的是一個(gè)流對象,而不是后者的字符串。因?yàn)槲覀兝@過了 Flask 的模板渲染函數(shù),而是直接使用了模板對象,所以我們手動(dòng)必須調(diào)用 update_template_context() 函數(shù)來確保更新了模板的渲染上下文。 這一模板隨后以流的方式迭代直到結(jié)束。因?yàn)槊恳淮文褂檬褂靡粋€(gè) yield 。服務(wù)器 都會(huì)將所有的已經(jīng)產(chǎn)生的內(nèi)容塞給給客戶端,因可能希望在模板中緩沖一部分元素 之后再發(fā)送,而不是每次都直接發(fā)送。您可以使用 rv.enable_buffering(size) 來實(shí)現(xiàn),size 的較為合理的默認(rèn)值是 5 。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號