[英]How to jsonify objects from sqlalchemy?
I'm using Flask, SQLAlchemy and javascript. 我正在使用Flask,SQLAlchemy和javascript。 I need to pass the results of my query to javascript in the json format, through AJAX, but I keep getting this error: 我需要通过AJAX将查询结果以json格式传递给javascript,但是我一直收到此错误:
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <model.Cloud object at 0x7f72e40c5910> is not JSON serializable'
My code is as follows: 我的代码如下:
@app.route('/past/<user_id>')
def get_past_clouds(user_id):
if user_id:
clouds = model_session.query(model.User).filter_by(id=user_id).first().clouds
if clouds != "":
clouds_d = {}
for idx, cloud in enumerate(clouds):
clouds_d[idx] = cloud
return jsonify(json_list=clouds_d)
return None
Ignore my previous comment, that allowed the request to work but all the objects returned were undefined. 忽略我之前的评论,该评论允许请求工作,但返回的所有对象均未定义。
This is how I did it in the end: 这是我最后做的事情:
clouds_d = dict( (cloud.name, [ photo.to_dict() for photo in cloud.photos ]) for cloud in clouds )
return jsonify(clouds_d)
As you've discovered, SQLAlchemy models are not natively serializable to JSON. 正如您所发现的,SQLAlchemy模型不能本地化为JSON序列化。
The approach you adopted - to manually construct a dict from your model instance's properties - gets the job done, but if you need to jsonify multiple models, deal with value conversions on serialization, or support deserialization (converting JSON back to a SQLAlchemy model instance) you'll find yourself writing a lot of tedious code. 您采用的方法-从模型实例的属性手动构建字典-完成工作,但是如果您需要对多个模型进行JSON处理,在序列化中处理值转换或支持反序列化(将JSON转换回SQLAlchemy模型实例)您会发现自己编写了大量繁琐的代码。
A better solution is to use a serialization/deserialization extension library for SQLAlchemy, such as either SQLAthanor or Marshmallow-SQLAlchemy (full disclosure: I am the author of SQLAthanor). 更好的解决方案是对SQLAlchemy使用序列化/反序列化扩展库,例如SQLAthanor或Marshmallow-SQLAlchemy (完整披露:我是SQLAthanor的作者)。
Using either of these libraries, you can basically serialize and deserialize SQLAlchemy models to other formats or deserialize them back into SQLAlchemy model instances. 使用这些库中的任何一个,您基本上都可以将SQLAlchemy模型序列化和反序列化为其他格式,或者将它们反序列化回SQLAlchemy模型实例。
In the case of SQLAthanor, you can basically get the job done with one method call: 对于SQLAthanor,基本上可以通过一个方法调用来完成工作:
json_result = model_instance.dump_to_json()
or (with some more configuration that gives you more fine-grained control): 或(具有更多配置,可让您进行更细粒度的控制):
json_result = model_instance.to_json()
You can also serialize to dict, or YAML, or CSV. 您还可以序列化为dict,YAML或CSV。
The reverse process is: 反向过程是:
model_instance = ModelClass.new_from_json(json_result)
Hope this helps! 希望这可以帮助!
Based on TypeError: <model.Cloud object at 0x7f72e40c5910> is not JSON serializable'
it seems in your clouds_d dictionary has a Cloud object nested inside. 基于TypeError: <model.Cloud object at 0x7f72e40c5910> is not JSON serializable'
,似乎在clouds_d词典中嵌套了一个Cloud对象。 please like print clouds_d
请喜欢print clouds_d
Like the error message says, you cannot call jsonify
on a SQLAlchemy model object (I don't think you can pickle them either). 就像错误消息所述,您不能在SQLAlchemy模型对象上调用jsonify
(我也不认为您也可以使它们腌制)。 Try: 尝试:
clouds_d[idx] = dict((k, cloud.__dict__[k]) for k in cloud.__dict__ if k[0] != '_')
or better yet, be explicit: 或者更好的是,要明确:
clouds_d[idx] = {
'id': cloud.id,
'other_attrs': '...',
}
After some more fiddling around, I fixed it, here's how: 经过一些摆弄后,我将其修复,方法如下:
@app.route('/past/<user_id>')
def get_past_clouds(user_id):
if user_id:
clouds = model_session.query(model.User).filter_by(id=user_id).first().clouds
if clouds != "":
clouds_d = {}
for idx, cloud in enumerate(clouds):
clouds_d[idx] = [ photo.path + photo.filename for photo in cloud.photos ]
print "clouds: ", clouds_d
return json.dumps(clouds_d)
return None
It looks like SQLAlchemy objects are not serializable, so I had to get out exactly what I wanted from the objects it was returning. 看起来SQLAlchemy对象是不可序列化的,所以我不得不从返回的对象中确切地弄出我想要的东西。
Here is my solution written in python: 这是我用python编写的解决方案:
step 1: custom JSON.encoder
步骤1:自定义JSON.encoder
import json
import uuid
from pprint import pformat
from datetime import datetime
from collections import OrderedDict
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
# cls = self.__class__
if isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
elif isinstance(obj, uuid.UUID):
return str(obj)
elif hasattr(obj, '__html__'):
return str(obj.__html__())
elif isinstance(obj, OrderedDict):
m = json.dumps(obj)
elif hasattr(obj, 'to_dict'):
return obj.to_dict()
else:
mp = pformat(obj, indent=2)
print("JsonEncodeError", type(obj), mp)
m = json.JSONEncoder.default(self, obj)
return m
step 2: override flask_app.json_encoder
第2步:覆盖flask_app.json_encoder
from flask import Flask
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder
step 3: Custom A Helper Class
for metaclass
of sqlalchemy 步骤3:为metaclass
自定义一个Helper Class
class CoModel():
"""
A `Helper Class` for `metaclass` of sqlalchemy
usage 1 : flask_sqlalchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(session_options=session_options)
class TableName(db.Model, CoModel):
pass
usage 2: sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class TableName(Base, CoModel):
__tablename__ = 'table_name'
"""
def to_dict(self):
result = {}
columns = self.columns()
for col in columns:
name = col.name
value = getattr(self, name)
result[name] = value
return result
@classmethod
def columns(cls):
tbl = getattr(cls, "__table__", None)
if tbl is None:
raise NameError('use sample: class TableName(db.Model, CoModel)')
else:
return tbl.columns
Finally, if you response with flask.jsonify
, it will be auto encoded by CoModel.to_dict()
最后,如果您使用flask.jsonify
响应,它将由CoModel.to_dict()
自动编码
Of course, you can use json.dumps(sqlalchmey_object,cls=CustomJSONEncoder)
as well. 当然,您也可以使用json.dumps(sqlalchmey_object,cls=CustomJSONEncoder)
。
Using marshmallow-sqlalchemy schemas, I'm generating an object and returning the serializable JSON object as a native method for the model. 使用棉花糖-sqlalchemy模式,我正在生成一个对象,并将可序列化的JSON对象作为模型的本机方法返回。 Here is an example for a class of Customer
in SQLAlchemy model. 这是SQLAlchemy模型中的Customer
类的示例。
from models import db
import datetime
from marshmallow_sqlalchemy import ModelSchema
class Customer(db.Model):
__tablename__ = 'customers'
__table_args__ = {'schema': 'abc_schema'}
id = db.Column(db.String(255), primary_key=True)
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
firstName = db.Column(db.String())
lastName = db.Column(db.String())
def __getitem__(self, item):
return getattr(self, item)
## Making the sql alchemy object JSON serailizable
def JSONSerializableObj(self):
class BaseSchema(ModelSchema):
def on_bind_field(self, field_name, field_obj):
field_obj.allow_none = True
class ObjectSchema(BaseSchema):
class Meta:
model = self
object_schema = ObjectSchema()
return object_schema.dump(self).data
This way, I'm just reusing this snippet for all models and using the JSONSerializableObj
这样,我只是为所有模型重用此代码段,并使用JSONSerializableObj
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.