0

I have this code:

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref

engine = sa.create_engine("sqlite:///:memory:")
session = scoped_session(sessionmaker(bind=engine))
Base = declarative_base()


class Author(Base):
    __tablename__ = "authors"
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String, nullable=False)
    books = relationship("Book", backref=backref("author", lazy="joined"),
                         foreign_keys="Book.author_id", lazy="dynamic")

    def __repr__(self):
        return "<Author(name={self.name!r})>".format(self=self)


class Book(Base):
    __tablename__ = "books"
    id = sa.Column(sa.Integer, primary_key=True)
    title = sa.Column(sa.String)
    author_id = sa.Column(sa.Integer, sa.ForeignKey("authors.id"))


Base.metadata.create_all(engine)


from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field, SQLAlchemyAutoSchema


class AuthorSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Author
        load_instance = True  # Optional: deserialize to model instances
        # dump_only = ("id",)
        include_fk = True


class BookSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Book
        load_instance = True
        # dump_only = ("id",)
        include_fk = True


author = Author(name="Chuck Paluhniuk")
author_schema = AuthorSchema()
book = Book(title="Fight Club", author=author)
book_schema = BookSchema()
session.add(author)
session.add(book)
session.commit()

dump_data_author = author_schema.dump(author)
print(dump_data_author)

dump_data_book = book_schema.dump(book)
print(dump_data_book)

When I run the code it prints:

{'id': 1, 'name': 'Chuck Paluhniuk'}
{'id': 1, 'author_id': 1, 'title': 'Fight Club'}

I want to change the code such that it prints:

{'id': 1, 'name': 'Chuck Paluhniuk', 'books': [{'id': 1, 'author_id': 1, 'title': 'Fight Club'}]}
{'id': 1, 'author_id': 1, 'title': 'Fight Club'}

How should I do this?

I want to have control over deserializing related objects.

I am also curious about some othe settings in the meta such load_only and dump_only and excelude, etc.

Amin Ba
  • 1,603
  • 1
  • 13
  • 38

1 Answers1

1

In my opinion, it is necessary to define nested fields in order to include relationships in the output in this way. You can define that the relationships are included automatically, but this only applies to the primary keys. In order not to use an override of a field, I have not included the relationships.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from flask_marshmallow import Marshmallow

app = Flask(__name__)
db = SQLAlchemy(app)
ma = Marshmallow(app)

class Author(db.Model):
    __tablename__ = "authors"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    books = db.relationship("Book",
        backref=db.backref("author", lazy="joined"),
        foreign_keys="Book.author_id",
        lazy="dynamic"
    )

class Book(db.Model):
    __tablename__ = "books"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    author_id = db.Column(db.Integer, db.ForeignKey("authors.id"))

class BookSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Book
        include_fk = True
        load_instance = True
        sqla_session = db.session

class AuthorSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Author
        load_instance = True
        # include_relationships = True # See below
        sqla_session = db.session
    books = ma.Nested(BookSchema, many=True)


with app.app_context():
    db.drop_all()
    db.create_all()

    author = Author(name="Chuck Paluhniuk")
    book = Book(title="Fight Club", author=author)
    db.session.add(author)
    db.session.add(book)
    db.session.commit()

    author_schema = AuthorSchema()
    book_schema = BookSchema()

    dump_data_author = author_schema.dump(author)
    print(dump_data_author)

    dump_data_book = book_schema.dump(book)
    print(dump_data_book)

    json = [
        {'author_id': 1, 'title': 'Fight Club', 'id': 1}
    ]
    schema = BookSchema(many=True)
    print(schema.load(json))

    json = [
        {'books': [{'author_id': 1, 'title': 'Fight Club', 'id': 1}], 'name': 'Chuck Paluhniuk', 'id': 1}
    ]
    schema = AuthorSchema(many=True)
    print(schema.load(json))
Detlef
  • 6,137
  • 2
  • 6
  • 24