序列化 Python Flask-Restless 的 Arrow 对象 API
Serializing Python Arrow objects for the Flask-Restless API
我目前正在使用 Flask-Restless 开发应用程序。当我用相应的 arrow fields, all went smoothly. This was due to the help of SQLAlchemy-Utils and its ArrowType 字段替换我的 SQLAlchemy 模型的典型 DateTime 字段时。
然而,在使用 API 到 return 这些对象的 JSON 表示之后,我收到以下错误:
类型错误:箭头 [2015-01-05T01:17:48.074707] 不是 JSON 可序列化的
修改模型序列化方式的理想位置在哪里?我是修改 Flask-Restless 代码以支持 Arrow 对象,还是编写 Flask-Restless 可以识别并用于检索 JSON 兼容对象的模型方法?
同时我也可以编写一个丑陋的后处理器函数,但该解决方案似乎是一个糟糕的 hack。
下面是一个带有 ArrowType 字段的示例模型:
class Novel(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.Unicode, unique=True, nullable=False)
created_at = db.Column(ArrowType, nullable=False)
def __init__(self, title):
self.title = title
self.created_at = arrow.utcnow()
支持箭头类型的自定义 JSONEncoder
怎么样?查看 Flask-Restless 源代码,它在底层使用了 Flask 的内置 jsonify
。有关以不同格式序列化常规 datetime
对象的示例,请参见此代码段:http://flask.pocoo.org/snippets/119/
这是一个完整的独立示例,可以很好地衡量:
import flask
import flask.ext.sqlalchemy
import flask.ext.restless
from flask.json import JSONEncoder
import sqlalchemy_utils
import arrow
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)
class Event(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(sqlalchemy_utils.ArrowType)
class ArrowJSONEncoder(JSONEncoder):
def default(self, obj):
try:
if isinstance(obj, arrow.Arrow):
return obj.format('YYYY-MM-DD HH:mm:ss ZZ')
iterable = iter(obj)
except TypeError:
pass
else:
return list(iterable)
return JSONEncoder.default(self, obj)
app.json_encoder = ArrowJSONEncoder
db.create_all()
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Event, methods=['GET','POST'])
app.run()
根据您 post 中的两个选项,我建议将方法添加到您的模型 class 中以检索 JSON 兼容的对象,只是因为它更简单且更多可维护的。如果你想修改 Flask-Restless,你需要 fork 或 monkey patch。
Arrow 现在有一个 for_json 方法。例如:arrow.utcnow().for_json()
我目前正在使用 Flask-Restless 开发应用程序。当我用相应的 arrow fields, all went smoothly. This was due to the help of SQLAlchemy-Utils and its ArrowType 字段替换我的 SQLAlchemy 模型的典型 DateTime 字段时。
然而,在使用 API 到 return 这些对象的 JSON 表示之后,我收到以下错误:
类型错误:箭头 [2015-01-05T01:17:48.074707] 不是 JSON 可序列化的
修改模型序列化方式的理想位置在哪里?我是修改 Flask-Restless 代码以支持 Arrow 对象,还是编写 Flask-Restless 可以识别并用于检索 JSON 兼容对象的模型方法?
同时我也可以编写一个丑陋的后处理器函数,但该解决方案似乎是一个糟糕的 hack。
下面是一个带有 ArrowType 字段的示例模型:
class Novel(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.Unicode, unique=True, nullable=False)
created_at = db.Column(ArrowType, nullable=False)
def __init__(self, title):
self.title = title
self.created_at = arrow.utcnow()
支持箭头类型的自定义 JSONEncoder
怎么样?查看 Flask-Restless 源代码,它在底层使用了 Flask 的内置 jsonify
。有关以不同格式序列化常规 datetime
对象的示例,请参见此代码段:http://flask.pocoo.org/snippets/119/
这是一个完整的独立示例,可以很好地衡量:
import flask
import flask.ext.sqlalchemy
import flask.ext.restless
from flask.json import JSONEncoder
import sqlalchemy_utils
import arrow
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)
class Event(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(sqlalchemy_utils.ArrowType)
class ArrowJSONEncoder(JSONEncoder):
def default(self, obj):
try:
if isinstance(obj, arrow.Arrow):
return obj.format('YYYY-MM-DD HH:mm:ss ZZ')
iterable = iter(obj)
except TypeError:
pass
else:
return list(iterable)
return JSONEncoder.default(self, obj)
app.json_encoder = ArrowJSONEncoder
db.create_all()
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Event, methods=['GET','POST'])
app.run()
根据您 post 中的两个选项,我建议将方法添加到您的模型 class 中以检索 JSON 兼容的对象,只是因为它更简单且更多可维护的。如果你想修改 Flask-Restless,你需要 fork 或 monkey patch。
Arrow 现在有一个 for_json 方法。例如:arrow.utcnow().for_json()