如何直接在自定义类(如FireO Models)中使用Flask的jsonify?

huangapple go评论76阅读模式
英文:

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来实现了所需的行为。但由于我在网上找到的大多数信息都已过时,以下是我是如何做到的。

  1. 创建一个自定义提供程序,扩展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()
  1. 将这个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.

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

huangapple
  • 本文由 发表于 2023年6月2日 02:15:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384645.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定