Skip to content

_sa_instance_state is dropped when SQLModels are nested. Is this expected?Β #375

@davepeck

Description

@davepeck

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google "How to X in SQLModel" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • I commit to help with one of those options πŸ‘†

Example Code

from sqlmodel import SQLModel, Session, create_engine, Field

engine = create_engine("sqlite:///:memory:")


class A(SQLModel, table=True):
    id: int | None = Field(primary_key=True)
    x: int

    def blow_up(self, session: Session):
        self.x = 42
        session.add(self)


class B(SQLModel):
    a: A

    def blow_up(self, session: Session):
        self.a.blow_up(session)


if __name__ == "__main__":
    SQLModel.metadata.create_all(engine)
    with Session(engine) as session:
        a = A(x=1)
        session.add(a)
        # Placing `a` inside a `B` instance appears to copy the `a` instance,
        # stripping `_sa_instance_state` from it. Is this intentional?
        b = B(a=a)
        b.blow_up(session)

Description

  • Create a SQLModel instance (a)
  • Create a non-table SQLModel (b) and nest a inside it
  • Note that b.a._sa_instance_state is not present, whereas a._instance_state is
  • The call to b.blow_up() will result in SQLAlchemy failing to find instance state
  File "/Users/me/.virtualenvs/sqlmodel-issue-u6SafBdE/lib/python3.10/site-packages/sqlalchemy/orm/attributes.py", line 2254, in set_attribute
    state, dict_ = instance_state(instance), instance_dict(instance)
AttributeError: 'A' object has no attribute '_sa_instance_state'

Operating System

macOS

Operating System Details

Monterey 12.4

SQLModel Version

0.0.6

Python Version

Python 3.10.4

Additional Context

My question is: what should the expected behavior here be?

Stepping back: nesting pydantic models like this is pretty natural; that's why I found this behavior surprising. But: perhaps nesting is not-so-natural when working with SQLModels? I'm not sure. The upshot is that you can't perform database operations on nested instances, for example, by calling b.a.some_method_that_does_database_stuff().

(The behavior is unchanged if B derives directly from pydantic.BaseModel, too.)

If the behavior we're seeing is not the desired behavior, I'm happy to contribute a PR, provided we have a clear understanding of what the right behavior should be.

Thanks for all the hard work on FastAPI, Typer, and SQLModel!

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions