J'ai une liste d'objets que je dois jsonifier. J'ai regardé le flask jsonify docs, mais je ne comprends tout simplement pas.
Ma classe a plusieurs variables d'installation, chacune étant une chaîne: gene_id
, gene_symbol
, p_value
. Que dois-je faire pour rendre cette opération sérialisable au format JSON?
Mon code naïf:
jsonify(eqtls = my_list_of_eqtls)
Résulte en:
TypeError: <__main__.EqtlByGene object at 0x1073ff790> is not JSON serializable
Je suppose que je dois dire à jsonify comment sérialiser un EqtlByGene
, mais je ne trouve pas d'exemple qui montre comment sérialiser une instance d'une classe.
Ce code fonctionne maintenant (merci beaucoup à Martijn Pieters!):
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 __== '__main__':
app.run(debug=True)
Lorsque je l'appelle via curl, je reçois:
{
"eqtls_by_gene": [
{
"gene_id": 1,
"gene_symbol": "EGFR",
"p_value": 0.1
},
{
"gene_id": 2,
"gene_symbol": "PTEN",
"p_value": 0.2
}
]
}
Donnez à votre EqltByGene
une méthode supplémentaire qui renvoie un dictionnaire:
class EqltByGene(object):
#
def serialize(self):
return {
'gene_id': self.gene_id,
'gene_symbol': self.gene_symbol,
'p_value': self.p_value,
}
utilisez ensuite une compréhension de liste pour transformer votre liste d'objets en une liste de valeurs sérialisables:
jsonify(eqtls=[e.serialize() for e in my_list_of_eqtls])
L’autre solution consisterait à écrire une fonction de crochet pour la fonction json.dumps()
, mais étant donné que votre structure est plutôt simple, l’approche basée sur la compréhension de liste et la méthode personnalisée sont plus simples.
Vous pouvez également être vraiment aventureux et sous-classe flask.json.JSONEncoder
; donnez-lui une méthode default()
qui convertit vos instances EqltByGene()
en une valeur sérialisable:
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)
et l'assigne à attribut app.json_encoder
:
app = Flask(__name__)
app.json_encoder = MyJSONEncoder
et passez votre liste directement à jsonify()
:
return jsonify(my_list_of_eqtls)
Si vous regardez la documentation pour le module json
, il est mentionné que vous pouvez sous-classe JSONEncoder
pour écraser sa méthode default
et ajouter un support pour les types là-bas. Ce serait le moyen le plus générique de le gérer si vous souhaitez sérialiser plusieurs structures différentes pouvant contenir vos objets.
Si vous souhaitez utiliser jsonify
, il est probablement plus facile de convertir vos objets en types simples à l’avance (par exemple, en définissant votre propre méthode sur la classe, comme le suggère Martijn).