如何将SqlAlchemy结果序列化为JSON?

发布于 2021-02-02 23:14:48

Django对从数据库返回到JSON格式的ORM模型具有良好的自动序列化功能。

如何将SQLAlchemy查询结果序列化为JSON格式?

我尝试过,jsonpickle.encode但是它编码查询对象本身。我试过了json.dumps(items)但是回来了

TypeError: <Product('3', 'some name', 'some desc')> is not JSON serializable

SQLAlchemy ORM对象序列化为JSON / XML真的很困难吗?没有默认的序列化程序吗?如今,序列化ORM查询结果是非常常见的任务。

我需要的只是返回SQLAlchemy查询结果的JSON或XML数据表示形式。

javascript datagird(JQGrid http://www.trirand.com/blog/)中需要使用JSON / XML格式的SQLAlchemy对象查询结果

关注者
0
被浏览
102
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    平面实施
    你可以使用如下形式:

    from sqlalchemy.ext.declarative import DeclarativeMeta
    
    class AlchemyEncoder(json.JSONEncoder):
    
        def default(self, obj):
            if isinstance(obj.__class__, DeclarativeMeta):
                # an SQLAlchemy class
                fields = {}
                for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
                    data = obj.__getattribute__(field)
                    try:
                        json.dumps(data) # this will fail on non-encodable values, like other classes
                        fields[field] = data
                    except TypeError:
                        fields[field] = None
                # a json-encodable dict
                return fields
    
            return json.JSONEncoder.default(self, obj)
    

    然后使用以下命令转换为JSON:

    c = YourAlchemyClass()
    print json.dumps(c, cls=AlchemyEncoder)
    

    它将忽略不可编码的字段(将它们设置为“无”)。

    它不会自动展开关系(因为这可能导致自我引用,并永远循环)。

    递归的非循环实现
    但是,如果你希望永久循环,则可以使用:

    from sqlalchemy.ext.declarative import DeclarativeMeta
    
    def new_alchemy_encoder():
        _visited_objs = []
    
        class AlchemyEncoder(json.JSONEncoder):
            def default(self, obj):
                if isinstance(obj.__class__, DeclarativeMeta):
                    # don't re-visit self
                    if obj in _visited_objs:
                        return None
                    _visited_objs.append(obj)
    
                    # an SQLAlchemy class
                    fields = {}
                    for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
                        fields[field] = obj.__getattribute__(field)
                    # a json-encodable dict
                    return fields
    
                return json.JSONEncoder.default(self, obj)
    
        return AlchemyEncoder
    

    然后使用以下代码编码对象:

    print json.dumps(e, cls=new_alchemy_encoder(), check_circular=False)
    

    这将对所有子项,所有子项以及所有子项进行编码。基本上,可能对整个数据库进行编码。当它到达之前已编码的内容时,会将其编码为“无”。

    递归(可能是循环的)选择性实现
    另一种可能更好的选择是能够指定要扩展的字段:

    def new_alchemy_encoder(revisit_self = False, fields_to_expand = []):
        _visited_objs = []
    
        class AlchemyEncoder(json.JSONEncoder):
            def default(self, obj):
                if isinstance(obj.__class__, DeclarativeMeta):
                    # don't re-visit self
                    if revisit_self:
                        if obj in _visited_objs:
                            return None
                        _visited_objs.append(obj)
    
                    # go through each field in this SQLalchemy class
                    fields = {}
                    for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
                        val = obj.__getattribute__(field)
    
                        # is this field another SQLalchemy object, or a list of SQLalchemy objects?
                        if isinstance(val.__class__, DeclarativeMeta) or (isinstance(val, list) and len(val) > 0 and isinstance(val[0].__class__, DeclarativeMeta)):
                            # unless we're expanding this field, stop here
                            if field not in fields_to_expand:
                                # not expanding this field: set it to None and continue
                                fields[field] = None
                                continue
    
                        fields[field] = val
                    # a json-encodable dict
                    return fields
    
                return json.JSONEncoder.default(self, obj)
    
        return AlchemyEncoder
    

    你现在可以通过以下方式调用它:

    print json.dumps(e, cls=new_alchemy_encoder(False, ['parents']), check_circular=False)
    

    例如,仅扩展名为“父母”的SQLAlchemy字段。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看