1. 程式人生 > >Flask設定返回json格式資料

Flask設定返回json格式資料

問題描述

在Flask中直接返回listdict是不行的,如

from flask import Flask

app = Flask(__name__)


@app.route('/')
def root():
    t = {
        'a': 1,
        'b': 2,
        'c': [3, 4, 5]
    }
    return t

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

這樣訪問會直接提示

TypeError: 'dict' object is
not callable

其原因是Flask並不會將list或dict預設轉換為json格式。

解決方法

HTTP返回json格式資料主要有兩個方面:
1. 資料本身為json格式;
2. Content-Type宣告為json格式。

使用標準庫json

比較常見的是採用標準庫json進行格式轉換:

from flask import Flask
import json

app = Flask(__name__)


@app.route('/')
def root():
    t = {
        'a': 1,
        'b': 2,
        'c'
: [3, 4, 5] } return json.dumps(t) if __name__ == '__main__': app.debug = True app.run()

這樣當訪問時即能夠正常得到json資料。但這麼做有一個缺點,就是HTTP返回的Content-Type仍然是text/html,即HTTP認為內容是HTML。

宣告Content-Type為json格式

在上面的解決方法上作一個加強,手動指定其Content-Typeapplication/json,通常採用的是修改Flask中的Response模組:

from flask import
Flask, Response import json app = Flask(__name__) @app.route('/') def root(): t = { 'a': 1, 'b': 2, 'c': [3, 4, 5] } return Response(json.dumps(t), mimetype='application/json') if __name__ == '__main__': app.debug = True app.run()

這樣不僅HTTP返回的內容是json,而且返回的Content-Type也是application/json了。

使用Flask的jsonify模組

實際上flask已經為json準備了專門的模組:jsonifyjsonify不僅會將內容轉換為json,而且也會修改Content-Typeapplication/json

from flask import Flask, jsonify

app = Flask(__name__)


@app.route('/')
def root():
    t = {
        'a': 1,
        'b': 2,
        'c': [3, 4, 5]
    }
    return jsonify(t)

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

自定義Flask的Response,使用force_type()

對於某些特殊的情況,可能並不想每個返回json資料的方法都使用jsonify()包起來,那有沒有什麼“非侵入式”的方法實現jsonify()的功能呢?其實是有的,不過這個方法相對比較高階。

Flask返回的內容實際是Response物件,return語句的內容實際是交給Response處理後才輸出由HTTP返回的;也就是說,之前直接返回dict報錯TypeError: 'dict' object is not callable也是Response乾的。那麼只需要在Response處理如dict等“非法”資料是,告訴Response該怎麼做就好了,這裡就是用到了其force_type()方法了,所有不能處理的資料,都由force_type()方法嘗試處理後,再決定報錯或通過。直接看例子吧。

from flask import Flask, Response, jsonify

class MyResponse(Response):
    @classmethod
    def force_type(cls, response, environ=None):
        if isinstance(response, (list, dict)):
            response = jsonify(response)
        return super(Response, cls).force_type(response, environ)

app = Flask(__name__)
app.response_class = MyResponse

@app.route('/')
def root():
    t = {
        'a': 1,
        'b': 2,
        'c': [3, 4, 5]
    }
    return t

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

或者還可以以繼承的方式來實現自定義Response,如:

from flask import Flask, Response, jsonify

class MyResponse(Response):
    @classmethod
    def force_type(cls, response, environ=None):
        if isinstance(response, (list, dict)):
            response = jsonify(response)
        return super(Response, cls).force_type(response, environ)

class MyFlask(Flask):
    response_class = MyResponse

app = MyFlask(__name__)

@app.route('/')
def root():
    t = {
        'a': 1,
        'b': 2,
        'c': [3, 4, 5]
    }
    return t

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