如何处理 marshmallow-sqlalchemy 中的嵌套关系
How to handle nested relationships in marshmallow-sqlalchemy
我有一个项目,我试图使用 marshmallow-sqlalchemy 包将数据从 JSON 加载到 Sqlalchemy 数据库中。该模型包含与子模型的一对多关系。
用一个作者多书的经典例子:
class Book(Base):
__tablename__ = "book"
id = Column(Integer, primary_key=True)
title = Column(String(50))
author_id = Column(Integer, ForeignKey("author.id"), nullable=False)
author = relationship("Author", backref=backref("books"))
class Author(Base):
__tablename__ = "author"
id = Column(Integer, primary_key=True)
name = Column(String(250))
books = relationship("Author", back_populates="author")
class BookSchema(ModelSchema):
class Meta:
model = Book
sqla_session = Session
class AuthorSchema(ModelSchema):
class Meta:
model = Author
sqla_session = Session
books = fields.Nested(BookSchema, many=True)
而输入JSON是
{
"name": "Author A",
"books": [
{"title": "Book 1"},
{"title": "Book 2"}
]
}
当我尝试加载 JSON 时,使用以下内容:
json_repr = {...}
author_schema = AuthorSchema()
obj_repr = author_schema.load(json_repr)
它在尝试反序列化文档时引发异常,指出 Book 是不可散列的类型。
发生了什么,我相信反序列化器正在尝试使用类似
的东西来创建对象
obj = model(**data)
这不适用于一对多关系,因为列表的实例需要 append()
到 Author.books 属性。
我一直无法在网络上的任何地方找到这种工作的任何示例,我看到的每个示例似乎都嵌套了一个实例,而不是一个列表。是否有推荐的方法使用 marshmallow-sqlalchemy 来完成此操作,或者我应该恢复使用直接的 marshmallow 包,并使用 @post_load 方法手动附加关系对象。
看来,处理这个问题的一种方法是在 sqlalchemy 模型上添加一个初始化器,它显式附加到集合中
class Author(Model):
__tablename__ = "author"
def __init__(self, books=None, *args, **kwargs):
super(Author, self).__init__(*args, **kwargs)
books = books or []
for book in books:
self.books.append(book)
仍然很好奇是否有更好的解决方案。
我遇到了与这个旧 post 类似的问题。设法在稍微不同的框架 Flask + SQLAlchemy + Marshmallow-SQLAlchemy(版本 2)下修复此 post。发布代码以备不时之需。
大部分更改为 models.py
- 换行
books = relationship("Book", back_populates="author")
- 使用
back_populates
而不是 backref
因为我收到错误 sqlalchemy.exc.ArgumentError: Error creating backref 'books' on relationship 'Book.author': property of that name exists on mapper 'mapped class Author->author
models.py
class Book(db.Model):
__tablename__ = "book"
id = Column(db.Integer, primary_key=True)
title = Column(db.String(50))
author_id = Column(db.Integer, db.ForeignKey("author.id"), nullable=False)
author = relationship("Author", back_populates="books")
class Author(db.Model):
__tablename__ = "author"
id = Column(db.Integer, primary_key=True)
name = Column(db.String(250))
books = relationship("Book", back_populates="author")
schemas.py - 基本相同
class BookSchema(ModelSchema):
class Meta:
model = Book
sqla_session = db.session
class AuthorSchema(ModelSchema):
class Meta:
model = Author
sqla_session = db.session
books = fields.Nested(BookSchema, many=True)
views.py
@api.route('/author/', methods=['POST'])
def new_author():
schema = AuthorSchema()
author = schema.load(request.get_json())
db.session.add(author.data) # version 2 marshmallow
db.session.commit()
return jsonify({"success": True})
我有一个项目,我试图使用 marshmallow-sqlalchemy 包将数据从 JSON 加载到 Sqlalchemy 数据库中。该模型包含与子模型的一对多关系。
用一个作者多书的经典例子:
class Book(Base):
__tablename__ = "book"
id = Column(Integer, primary_key=True)
title = Column(String(50))
author_id = Column(Integer, ForeignKey("author.id"), nullable=False)
author = relationship("Author", backref=backref("books"))
class Author(Base):
__tablename__ = "author"
id = Column(Integer, primary_key=True)
name = Column(String(250))
books = relationship("Author", back_populates="author")
class BookSchema(ModelSchema):
class Meta:
model = Book
sqla_session = Session
class AuthorSchema(ModelSchema):
class Meta:
model = Author
sqla_session = Session
books = fields.Nested(BookSchema, many=True)
而输入JSON是
{
"name": "Author A",
"books": [
{"title": "Book 1"},
{"title": "Book 2"}
]
}
当我尝试加载 JSON 时,使用以下内容:
json_repr = {...}
author_schema = AuthorSchema()
obj_repr = author_schema.load(json_repr)
它在尝试反序列化文档时引发异常,指出 Book 是不可散列的类型。
发生了什么,我相信反序列化器正在尝试使用类似
的东西来创建对象obj = model(**data)
这不适用于一对多关系,因为列表的实例需要 append()
到 Author.books 属性。
我一直无法在网络上的任何地方找到这种工作的任何示例,我看到的每个示例似乎都嵌套了一个实例,而不是一个列表。是否有推荐的方法使用 marshmallow-sqlalchemy 来完成此操作,或者我应该恢复使用直接的 marshmallow 包,并使用 @post_load 方法手动附加关系对象。
看来,处理这个问题的一种方法是在 sqlalchemy 模型上添加一个初始化器,它显式附加到集合中
class Author(Model):
__tablename__ = "author"
def __init__(self, books=None, *args, **kwargs):
super(Author, self).__init__(*args, **kwargs)
books = books or []
for book in books:
self.books.append(book)
仍然很好奇是否有更好的解决方案。
我遇到了与这个旧 post 类似的问题。设法在稍微不同的框架 Flask + SQLAlchemy + Marshmallow-SQLAlchemy(版本 2)下修复此 post。发布代码以备不时之需。
大部分更改为 models.py
- 换行
books = relationship("Book", back_populates="author")
- 使用
back_populates
而不是backref
因为我收到错误sqlalchemy.exc.ArgumentError: Error creating backref 'books' on relationship 'Book.author': property of that name exists on mapper 'mapped class Author->author
models.py
class Book(db.Model):
__tablename__ = "book"
id = Column(db.Integer, primary_key=True)
title = Column(db.String(50))
author_id = Column(db.Integer, db.ForeignKey("author.id"), nullable=False)
author = relationship("Author", back_populates="books")
class Author(db.Model):
__tablename__ = "author"
id = Column(db.Integer, primary_key=True)
name = Column(db.String(250))
books = relationship("Book", back_populates="author")
schemas.py - 基本相同
class BookSchema(ModelSchema):
class Meta:
model = Book
sqla_session = db.session
class AuthorSchema(ModelSchema):
class Meta:
model = Author
sqla_session = db.session
books = fields.Nested(BookSchema, many=True)
views.py
@api.route('/author/', methods=['POST'])
def new_author():
schema = AuthorSchema()
author = schema.load(request.get_json())
db.session.add(author.data) # version 2 marshmallow
db.session.commit()
return jsonify({"success": True})