Django可以很好地自动序列化从DB返回到JSON格式的ORM模型.

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

我try 了jsonpickle.encode,但它对查询对象本身进行了编码.

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

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

我只需要返回SQLAlChemy查询结果的JSON或XML数据表示.

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

推荐答案

A flat implementation

你可以用这样的方法:

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)

它将忽略不可编码的字段(将其设置为"无").

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

A recursive, non-circular implementation

但是,如果您希望永远循环,可以使用:

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)

这将对所有的子元素,他们的子元素,他们的子元素进行编码...基本上,可以对整个数据库进行编码.当它到达之前编码的东西时,它会将其编码为"无".

A recursive, possibly-circular, selective implementation

另一种可能更好的替代方法是能够指定要扩展的字段:

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)

例如,仅扩展名为"parents"的SQLAlchemy字段.

Python相关问答推荐

将两个收件箱相连导致索引的列标题消失

按日期和组增量计算总价值

使用decorator 自动继承父类

如何判断. text文件中的某个字符,然后读取该行

已安装' owiener ' Python模块,但在导入过程中始终没有名为owiener的模块

尽管进程输出错误消息,subProcess.check_call的CalledProcess错误.stderr为无

在后台运行的Python函数

如何才能将每个组比上一组增加N %?

如何让pyparparsing匹配1天或2天,但1天和2天失败?

查找下一个值=实际值加上使用极点的50%

使用FASTCGI在IIS上运行Django频道

Pandas 有条件轮班操作

通过Selenium从页面获取所有H2元素

如何找到满足各组口罩条件的第一行?

如何请求使用Python将文件下载到带有登录名的门户网站?

如何获得每个组的时间戳差异?

如何在表中添加重复的列?

转换为浮点,pandas字符串列,混合千和十进制分隔符

名为__main__. py的Python模块在导入时不运行'

什么是合并两个embrame的最佳方法,其中一个有日期范围,另一个有日期没有任何共享列?