Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Dictionary Collections (collection=attribute_keyed_dict) #580

Open
jsormaz opened this issue Apr 16, 2024 · 1 comment
Open

Comments

@jsormaz
Copy link

jsormaz commented Apr 16, 2024

In sqlalchemy I can map a collection as a dictionary rather than a list:
https://docs.sqlalchemy.org/en/20/orm/collection_api.html#dictionary-collections

Is this supported at all by marshmallow-sqlalchemy?

@sloria
Copy link
Member

sloria commented Jan 12, 2025

You can deserialize to nested dictionaries for relationships by passing columns to auto_field

from pprint import pprint

import sqlalchemy as sa
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker

from marshmallow_sqlalchemy import SQLAlchemyAutoSchema, auto_field


class Base(DeclarativeBase):
    pass


class User(Base):
    __tablename__ = "user"
    id = sa.Column(sa.Integer, primary_key=True)
    full_name = sa.Column(sa.String(255))

    blog_posts = relationship(lambda: BlogPost, back_populates="author")


class BlogPost(Base):
    __tablename__ = "blog_post"
    id = sa.Column(sa.Integer, primary_key=True)
    title = sa.Column(sa.String(255), nullable=False)

    author_id = sa.Column(sa.Integer, sa.ForeignKey(User.id), nullable=False)
    author = relationship(User)


class AuthorSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = User
        include_relationships = True

    blog_posts = auto_field(columns=("id", "title"))


engine = sa.create_engine("sqlite:///:memory:")
Session = sessionmaker(engine)

Base.metadata.create_all(engine)

with Session() as session:
    user = User(full_name="Freddie Mercury")
    post = BlogPost(title="Bohemian Rhapsody Revisited", author=user)

    session.add_all([user, post])
    session.commit()

    assert len(user.blog_posts) == 1
    session.refresh(user)

    dumped_user = AuthorSchema().dump(user)
    pprint(dumped_user, indent=2)
    # { 'blog_posts': [{'id': 1, 'title': 'Bohemian Rhapsody Revisited'}],
    #   'full_name': 'Freddie Mercury',
    #   'id': 1}

However, if User.blog_posts model is changed to use, attribute_keyed_dict, the serialized input is broken

class User(Base):
    __tablename__ = "user"
    id = sa.Column(sa.Integer, primary_key=True)
    full_name = sa.Column(sa.String(255))

    blog_posts = relationship(
        lambda: BlogPost,
        back_populates="author",
        collection_class=attribute_keyed_dict("id"),
    )
    dumped_user = AuthorSchema().dump(user)
    pprint(dumped_user, indent=2)
    # { 'blog_posts': [{'id': 1, 'title': 'Bohemian Rhapsody Revisited'}],
    #   'full_name': 'Freddie Mercury',
    #   'id': 1}

i'll leave this issue open as a feature request to support attribute_keyed_dict

@sloria sloria changed the title Support for Dictionary Collections Support for Dictionary Collections (collection=attribute_keyed_dict) Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants