web-dev-qa-db-fra.com

Flask jsonify une liste d'objets

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
    }
  ]
}
49
Jared Nedzel

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)
72
Martijn Pieters

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).

3
Amber