英文:
How to directly use Flask's jsonify with custom classes like FireO Models?
问题
我正在使用Flask版本2.3.2和FireO ORM 2.1.0
FireO模型与Flask的jsonify不是直接兼容的。这意味着它们不会默认被序列化,需要在传递给jsonify之前将它们转换成字典。
例如:
users_dicts = [user.to_dict() for user in users]
return jsonify(users_dicts), 200
或者
return jsonify(user.to_dict()), 200
所以我的想法是要么扩展FireO模型,要么扩展Flask,这样我就可以这样做:
jsonify(users), 200 # Users是一个FireO QueryIterator
jsonify(user), 200 # User是一个FireO模型
英文:
I'm using Flask version 2.3.2 and FireO ORM 2.1.0
FireO models are not directly compatible with Flask's jsonify. Meaning that they are not serializables by default and need to be converted into a dictionary before passing them to jsonify.
Ex:
users_dicts = [user.to_dict() for user in users]
return jsonify(users_dicts), 200
# or
return jsonify(user.to_dict()), 200
So my idea was to extend either FireO Models or Flask so I could just do:
jsonify(users), 200 # Users is a FireO QueryIterator
jsonify(user), 200 # User is a FireO model
答案1
得分: 2
我认为,如果您重写 DefaultJSONProvider.dumps
,那么该函数仅在顶级对象上调用一次,因此任何委托/递归都必须手动完成。
我更容易提供一个静态重写的示例,用于 DefaultJSONProvider.default
:
class ModelProvider(DefaultJSONProvider):
@staticmethod
def default(obj):
if isinstance(obj, Model):
return obj.to_dict()
else:
return DefaultJSONProvider.default(obj)
英文:
I think if you override DefaultJSONProvider.dumps
, that function is only called once for the top-level object, so any delegation/recursion has to be done by hand.
I had a much easier time providing a static override for DefaultJSONProvider.default
:
class ModelProvider(DefaultJSONProvider):
@staticmethod
def default(obj):
if isinstance(obj, Model):
return obj.to_dict()
else:
return DefaultJSONProvider.default(obj)
答案2
得分: 1
我通过扩展Flask的DefaultJSONProvider来实现了所需的行为。但由于我在网上找到的大多数信息都已过时,以下是我是如何做到的。
- 创建一个自定义提供程序,扩展DefaultJSONProvider。它会检查要序列化的对象是否是相关的FireO类之一,并将它们转换为字典或字典数组。对于其他任何情况,它将默认回到DefaultJSONProvider的行为。
from datetime import datetime
from fireo.models import Model
from fireo.queries.query_iterator import QueryIterator
from flask.json.provider import DefaultJSONProvider
class CustomJsonProvider(DefaultJSONProvider):
def dumps(self, obj, **kw):
"""
Define how to serialize objects that aren't natively serializable by json.dumps.
Returns:
- A dictionary if the object is a FireO model
- A list of dictionaries if the object is a FireO QueryIterator or list of models
- Datetime objects are serialized to iso strings
- All other clases are delegated back to DefaultJSONProvider
"""
if isinstance(obj, Model):
obj = obj.to_dict()
self.datetime_to_string(obj)
elif (isinstance(obj, QueryIterator)
or (isinstance(obj, list) and all(isinstance(item, Model) for item in obj))):
obj = [item.to_dict() for item in obj]
# all datetimes to strings
for item in obj:
self.datetime_to_string(item)
return super().dumps(obj, **kw) # Delegate to the default dumps
def datetime_to_string(self, obj):
# Convert all datetimes in the dictionary to string
for key, value in obj.items():
if isinstance(value, datetime):
obj[key] = value.isoformat()
- 将这个CustomJsonProvider传递给Flask的应用程序:
app = Flask(__name__)
app.json_provider_class = CustomJsonProvider
app.json = CustomJsonProvider(app)
P.S: 我希望扩展FireO的Model类,但我在理解Flask的jsonify和dumps的内部工作方式方面遇到了一些困难,特别是它们对于类的序列化需要什么。在这方面有任何建议吗?
英文:
I achieved the desired behavior by extending Flask's DefaultJSONProvider. But as the majority of the information that I found online was outdated, here is how I did it.
- A custom provider extending DefaultJSONProvider. It checks if the object to serialize is one of the relevant FireO classes and converts them into a dictionary or array of dictionaries. For anything else, it defaults back to DefaultJSONProvider behaviour.
from fireo.models import Model
from fireo.queries.query_iterator import QueryIterator
from flask.json.provider import DefaultJSONProvider
class CustomJsonProvider(DefaultJSONProvider):
def dumps(self, obj, **kw):
"""
Define how to serialize objects that aren't natively serializable by json.dumps.
Returns:
- A dictionary if the object is a FireO model
- A list of dictionaries if the object is a FireO QueryIterator or list of models
- Datetime objects are serialized to iso strings
- All other clases are delegated back to DefaultJSONProvider
"""
if isinstance(obj, Model):
obj = obj.to_dict()
self.datetime_to_string(obj)
elif (isinstance(obj, QueryIterator)
or (isinstance(obj, list) and all(isinstance(item, Model) for item in obj))):
obj = [item.to_dict() for item in obj]
# all datetimes to strings
for item in obj:
self.datetime_to_string(item)
return super().dumps(obj, **kw) # Delegate to the default dumps
def datetime_to_string(self, obj):
# Convert all datetimes in the dictionary to string
for key, value in obj.items():
if isinstance(value, datetime):
obj[key] = value.isoformat()
- Pass this CustomJsonProvider to Flask's app:
app = Flask(__name__)
app.json_provider_class = CustomJsonProvider
app.json = CustomJsonProvider(app)
P.S: I was hoping to extend FireO's Model classes, but I'm having some difficulties understanding the inner workings of Flask's jsonify and dumps, especially what they require for class serialization.Any advice here would be great.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论