Django有一些从DB到JSON格式返回的ORM模型的自动序列化。
如何将SQLAlchemy查询结果序列化为JSON格式?
我尝试了jsonpickle.encode,但它对查询对象本身进行了编码。
我试过json.dumps(items)但它返回了
TypeError: is not JSON serializable
是否真的很难将SQLAlchemy ORM对象序列化为JSON / XML? 它没有默认的序列化器吗? 现在序列化ORM查询结果是非常常见的任务。
我需要的只是返回SQLAlchemy查询结果的JSON或XML数据表示。
需要在javascript datagird中使用SQLAlchemy对象的JSON / XML格式的查询结果(JQGrid http://www.trirand.com/blog/)
您可以将对象输出为dict:
class User:
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
然后使用User.as_dict()来序列化您的对象。
如将sqlalchemy行对象转换为python dict中所述
@charlax,我如何修复DateTime?通过使用这个我得到'datetime.datetime(2013,3,22,16,50,11)不是JSON序列化'当我做json.dumps
这是JSONEncoder对象的责任。您可以将其子类化为某个对象定义自己的编码器,包括datetime。请注意,Flask例如支持在JSON中开箱即用(使用最新版本)编码日期时间。
如果您使用sqlalchemy的"声明"方法,您可以将这样的内容添加到自定义Base类 - 这非常方便,因为您可以在任何ORM对象上调用my_orm_object.toDict()。类似地,您可以定义.toJSON()方法,该方法使用toDict方法和自定义编码器来处理日期,blob等
如何处理急切加载的关系?
我会避免倾销关系,并依赖客户端连接。如果你绝对想要包含关系,你可以有一个明确的列表,并在它们上面调用as_dict,或者你可以想象使用operator.attrgetter并明确所有内容。还有一种方法可以以编程方式在模型上建立关系。
还支持日期时间:return {c.name: unicode(getattr(self, c.name)) for c in self.__table__.columns}
无需修改自己的as_dict()转换,结果集中的行具有内部dict方法。试试这个:``import json rs = YourModel.query.all()s = json.dumps([r .__ dict__ for r in rs],default = alchemyencoder)print"result:"+ s``
如果您的类变量与列名称不同,则此方法无效。不知道如何获取类名吗?
但是如何编写解串器或这个模型呢?我是否必须为每个Column类编写代码?
@JamesBurke - 在这里查看(我的)答案的"更难的案例"部分。但是,像:{a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
平面实施
你可以使用这样的东西:
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