Flask jsonify 对象列表

Posted

技术标签:

【中文标题】Flask jsonify 对象列表【英文标题】:Flask jsonify a list of objects 【发布时间】:2014-02-20 02:24:03 【问题描述】:

我有一个需要 jsonify 的对象列表。我查看了烧瓶 jsonify 文档,但我就是不明白。

我的班级有几个 inst-var,每个都是一个字符串:gene_idgene_symbolp_value。我需要做什么才能将其序列化为 JSON?

我的幼稚代码:

jsonify(eqtls = my_list_of_eqtls)

结果:

TypeError: <__main__.EqtlByGene object at 0x1073ff790> is not JSON serializable

大概我必须告诉 jsonify 如何序列化 EqtlByGene,但我找不到显示如何序列化类实例的示例。

我一直在尝试按照下面显示的一些建议来创建我自己的 JSONEncoder 子类。我的代码现在是:

class EqtlByGene(Resource):

    def __init__(self, gene_id, gene_symbol, p_value):
        self.gene_id = gene_id
        self.gene_symbol = gene_symbol
        self.p_value = p_value

class EqtlJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, EqtlByGene):
            return 
                   'gene_id'     : obj.gene_id,
                   'gene_symbol' : obj.gene_symbol,
                   'p_value'     : obj.p_value
            
        return super(EqtlJSONEncoder, self).default(obj)

class EqtlByGeneList(Resource):
    def get(self):
        eqtl1 = EqtlByGene(1, 'EGFR', 0.1)
        eqtl2 = EqtlByGene(2, 'PTEN', 0.2)
        eqtls = [eqtl1, eqtl2]
        return jsonify(eqtls_by_gene = eqtls)

api.add_resource(EqtlByGeneList, '/eqtl/eqtlsbygene')
app.json_encoder(EqtlJSONEncoder)
if __name__ == '__main__':
    app.run(debug=True)

当我尝试通过 curl 访问它时,我得到:

TypeError(repr(o) + " is not JSON serializable")

【问题讨论】:

JSON 无法序列化类实例。但是,您决定序列化您的类,该序列化将不是规范的 JSON,并且在反序列化您的 JSON 时需要另一方的显式支持。 【参考方案1】:

给你的EqltByGene 一个额外的方法来返回一个字典:

class EqltByGene(object):
    #

    def serialize(self):
        return 
            'gene_id': self.gene_id, 
            'gene_symbol': self.gene_symbol,
            'p_value': self.p_value,
        

然后使用列表推导将您的对象列表转换为可序列化值的列表:

jsonify(eqtls=[e.serialize() for e in my_list_of_eqtls])

另一种方法是为json.dumps() 函数编写一个钩子函数,但由于您的结构相当简单,列表理解和自定义方法方法更简单。

你也可以是真正的冒险者和子类flask.json.JSONEncoder;给它一个 default() 方法,将你的 EqltByGene() 实例变成一个可序列化的值:

from flask.json import JSONEncoder

class MyJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, EqltByGene):
            return 
                'gene_id': obj.gene_id, 
                'gene_symbol': obj.gene_symbol,
                'p_value': obj.p_value,
            
        return super(MyJSONEncoder, self).default(obj)

并将其分配给app.json_encoder attribute:

app = Flask(__name__)
app.json_encoder = MyJSONEncoder

只需将您的列表直接传递给jsonify()

return jsonify(my_list_of_eqtls)

您还可以查看Marshmallow project 以获得更成熟和灵活的项目,用于将对象序列化和反序列化为易于适应 JSON 和其他此类格式的 Python 原语;例如:

from marshmallow import Schema, fields

class EqltByGeneSchema(Schema):
    gene_id = fields.Integer()
    gene_symbol = fields.String()
    p_value = fields.Float()

然后使用

jsonify(eqlts=EqltByGeneSchema().dump(my_list_of_eqtls, many=True)

生成 JSON 输出。相同的架构可用于验证传入的 JSON 数据,并(使用 appropriate extra methods)再次生成 EqltByGene 实例。

【讨论】:

@Martijn Pieters:我试过了:code class EqtlJSONEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, EqtlByGene): return 'gene_id' : obj.gene_id, 'gene_symbol' : obj.gene_symbol, 'p_value' : obj.p_value return JSONEncoder.default(self, obj) .... app.json_encoder(EqtlJSONEncoder) code 但我还是得到了: @user1438352:我已经更新了代码并在本地进行了测试;它现在对我来说可以正常工作了。 我一定是做错了什么。我仍然得到: TypeError: <__main__.eqtlbygene object at> is not JSON serializable @user1438352:那么default 处理程序无法识别您的类类型; isinstance(obj, EqltByGene) 出于某种原因不正确。是否正在执行该 if 语句下的 print 语句? Martijn,不,它没有进入 if 语句。【参考方案2】:

如果您查看the docs for the json module,它提到您可以subclass JSONEncoder to override its default method 并在那里添加对类型的支持。如果您要序列化可能包含您的对象的多个不同结构,那将是最通用的处理方式。

如果您想使用jsonify,提前将对象转换为简单类型可能更容易(例如,通过在类上定义自己的方法,正如 Martijn 建议的那样)。

【讨论】:

对不起,我是python新手。我查看了那些文档,这对我来说只是胡言乱语。你能举个例子吗? @MartijnPieters 我以为jsonify 通过了*args, **kwargs?无论如何,这可能是最好不要使用 jsonify 的时候。 @Amber:是的,这些参数被传递给dict(),然后那个被传递给json.dumps()

以上是关于Flask jsonify 对象列表的主要内容,如果未能解决你的问题,请参考以下文章

jsonify Flask中的SQLAlchemy结果集[重复]

Flask 学习-88. jsonify() 函数源码解读深入学习

在flask中使用jsonify和json.dumps的区别

Flask 中字典数据返回(jsonify)

为啥flask的jsonify方法很慢?

防止 Flask jsonify 对数据进行排序