我正在使用Flask,SQLAlchemy和javascript。我需要通过AJAX将我的查询结果传递给json格式的javascript,但我一直收到这个错误:
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <model.Cloud object at 0x7f72e40c5910> is not JSON serializable'
我的代码如下:
@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
忽略我以前的评论,该评论允许请求生效,但返回的所有对象都未定义。
这就是我最终的表现:
clouds_d = dict( (cloud.name, [ photo.to_dict() for photo in cloud.photos ]) for cloud in clouds )
return jsonify(clouds_d)
答案 0 :(得分:1)
您已经发现,SQLAlchemy模型不能本地化为JSON。
您采用的方法-从模型实例的属性中手动构建字典-完成工作,但是如果您需要对多个模型进行json处理,在序列化中处理值转换或支持反序列化(将JSON转换回SQLAlchemy模型实例),您会发现自己编写了大量繁琐的代码。
更好的解决方案是对SQLAlchemy使用序列化/反序列化扩展库,例如SQLAthanor或Marshmallow-SQLAlchemy(完整披露:我是SQLAthanor的作者)。
使用这两个库中的任何一个,您基本上都可以将SQLAlchemy模型序列化和反序列化为其他格式,或者将它们反序列化为SQLAlchemy模型实例。
对于SQLAthanor,基本上可以通过一个方法调用来完成工作:
json_result = model_instance.dump_to_json()
或(具有更多配置,可让您进行更细粒度的控制):
json_result = model_instance.to_json()
您还可以序列化为dict,YAML或CSV。
相反的过程是:
model_instance = ModelClass.new_from_json(json_result)
希望这会有所帮助!
答案 1 :(得分:0)
基于TypeError: <model.Cloud object at 0x7f72e40c5910> is not JSON serializable'
在你的clouds_d词典里面似乎有一个嵌套在里面的Cloud对象。请点赞print clouds_d
答案 2 :(得分:0)
就像错误消息所说的那样,你不能在SQLAlchemy模型对象上调用jsonify
(我认为你也不能腌制它们)。尝试:
clouds_d[idx] = dict((k, cloud.__dict__[k]) for k in cloud.__dict__ if k[0] != '_')
或更好,明确:
clouds_d[idx] = {
'id': cloud.id,
'other_attrs': '...',
}
答案 3 :(得分:0)
经过一些更多的摆弄,我修复了它,这是如何:
@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
看起来SQLAlchemy对象不可序列化,所以我不得不从它返回的对象中得到我想要的东西。
答案 4 :(得分:0)
这是我用python编写的解决方案:
步骤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
步骤2:覆盖flask_app.json_encoder
from flask import Flask
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder
第3步:为Helper Class
的sqlalchemy自定义A metaclass
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
最后,如果您回复flask.jsonify
,它将由CoModel.to_dict()
自动编码
当然,您也可以使用json.dumps(sqlalchmey_object,cls=CustomJSONEncoder)
。
答案 5 :(得分:0)
使用marshmallow-sqlalchemy模式,我正在生成一个对象,并将可序列化的JSON对象作为模型的本机方法返回。这是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
这样,我将对所有模型重新使用此代码段,并使用JSONSerializableObj