【问题标题】:Error deseralizing JSON string with nested objects with SqlAlchemy and Marshmallow使用 SqlAlchemy 和 Marshmallow 使用嵌套对象反序列化 JSON 字符串时出错
【发布时间】:2017-08-23 03:01:58
【问题描述】:

我正在尝试使用 Flask、SQLAlchemy 和 Marshmallow 在 Python 3.4 中构建一个 REST API 应用程序。

在我的模型中,我有一个 User 类,它与 MailAddress 类具有一对多关系。

如果我运行GET 请求,我设法从数据库中读取数据,并且数据作为 JSON 字符串正确返回。

相反,如果我使用带有一些MailAddressesUser 对象的JSON 序列化运行POST 请求,我会收到此错误:

    File "X:\test\...\site-packages\sqlalchemy\orm\collections.py", line 785, in bulk_replace 
      constants = existing_idset.intersection(values or ())
    File "X:\test\...\site-packages\sqlalchemy\util\_collections.py", line 612, in intersection
      result._members.update(self._working_set(members).intersection(other))
    TypeError: unhashable type: 'dict'

我尝试将__hash__ 函数添加到我的模型类中(如sqlalchemy: TypeError: unhashable type creating instance, sqlalchemy 所建议的那样),但这没有帮助。

这里有一个完整的代码示例来说明这个问题:

from flask import Flask, request
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from marshmallow import fields
from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship

class Config(object):
    SQLALCHEMY_DATABASE_URI = '<CONNECTION STRING HERE>'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
ma = Marshmallow(app)

# Model
class MailAddress(db.Model):
    __tablename__ = 'mail_addresses'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    mail_type = Column(String(200), nullable=False)
    mail = Column(String(200), nullable=False)
    def __init__(self, mail, mail_type):
        self.mail = mail
        self.mail_type = mail_type

class MailAddressSchema(ma.ModelSchema):
    class Meta:
        model = MailAddress

class User(db.Model):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False)
    mail_addresses = relationship('MailAddress', backref='user')
    def __init__(self, name, mail_addresses):
        self.name = name
        self.mail_addresses = mail_addresses
    def __hash__(self):
        return hash(self.name)

class UserSchema(ma.ModelSchema):
    mail_addresses = fields.Nested(MailAddressSchema, many = True, only=('mail', 'mail_type'))
    class Meta:
        model = User

# Routes
user_schema = UserSchema()

@app.route('/api/v0/user', methods=['GET'])
def user_get():
    users = db.session.query(User).all()
    return user_schema.jsonify(users, many = True), 200

@app.route('/api/v0/user', methods=['POST'])
def user_create():
    new_instance = user_schema.make_instance(request.json)
    db.session.add(new_instance)
    db.session.commit()
    return user_schema.jsonify(new_instance), 201

# Main
if __name__ == '__main__':
    app.run('localhost', 5555)

我有什么遗漏吗?

【问题讨论】:

    标签: python json sqlalchemy marshmallow


    【解决方案1】:

    使用load 代替make_instance

    @app.route('/api/v0/user', methods=['POST'])
    def user_create():
        new_instance, errors = user_schema.load(request.json)
        db.session.add(new_instance)
        db.session.commit()
        return user_schema.jsonify(new_instance), 201
    

    【讨论】:

    • 注意,在版本 3 中,load 方法返回反序列化的数据,而不是 (data, errors) 副本。见documentation
    猜你喜欢
    • 2019-09-11
    • 2016-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多