How to handle nested relationships in marshmallow-sqlalchemy

It appears, that one way of handling this is to add an initializer on the sqlalchemy model, which explicitly appends to the collection

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)

Still curious though if there is a better solution out there.


I was having similar issues to this old post. Managed to fix this post under a slightly different framework Flask + SQLAlchemy + Marshmallow-SQLAlchemy (version 2). Posted code in case helpful.

Most of change are to models.py

  1. Change of line books = relationship("Book", back_populates="author")
  2. Used back_populates instead of backref as I was getting error 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 - mostly same

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})