Флажок jsonify список объектов
У меня есть список объектов, которые мне нужно jsonify. Я посмотрел на флеш файлы jsonify, но я просто не понимаю.
Мой класс имеет несколько inst-vars, каждая из которых является строкой: gene_id
, gene_symbol
, p_value
. Что мне нужно сделать, чтобы сделать сериализуемым как JSON?
Мой наивный код:
jsonify(eqtls = my_list_of_eqtls)
Результаты в:
TypeError: <__main__.EqtlByGene object at 0x1073ff790> is not JSON serializable
Предположительно, я должен сказать jsonify, как сериализовать EqtlByGene
, но я не могу найти пример, который показывает, как сериализовать экземпляр класса.
Этот код теперь работает (с большим благодарением 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 __name__ == '__main__':
app.run(debug=True)
Когда я вызываю его через curl, я получаю:
{
"eqtls_by_gene": [
{
"gene_id": 1,
"gene_symbol": "EGFR",
"p_value": 0.1
},
{
"gene_id": 2,
"gene_symbol": "PTEN",
"p_value": 0.2
}
]
}
Ответы
Ответ 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])
Альтернативой было бы написать функцию hook для функции 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
:
app = Flask(__name__)
app.json_encoder = MyJSONEncoder
и просто перейдите в свой список непосредственно к jsonify()
:
return jsonify(my_list_of_eqtls)
Ответ 2
Если вы посмотрите документы для модуля json
, в нем упоминается, что вы можете подкласс JSONEncoder
, чтобы переопределить его метод default
и добавить поддержку типов там. Это был бы самый общий способ справиться с этим, если вы собираетесь сериализовать несколько разных структур, которые могут содержать ваши объекты.
Если вы хотите использовать jsonify
, возможно, вам проще просто преобразовать объекты в простые типы заблаговременно (например, определив свой собственный метод в классе, как предполагает Мартийн).