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

User Guide Example throws AttributeError #345

Closed
8 tasks done
mkrd opened this issue May 19, 2022 · 4 comments
Closed
8 tasks done

User Guide Example throws AttributeError #345

mkrd opened this issue May 19, 2022 · 4 comments
Labels
answered question Further information is requested

Comments

@mkrd
Copy link

mkrd commented May 19, 2022

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 typing import List, Optional

from sqlmodel import Field, Relationship, Session, SQLModel, create_engine


class Team(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    headquarters: str

    heroes: List["Hero"] = Relationship(back_populates="team")


class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    secret_name: str
    age: Optional[int] = Field(default=None, index=True)

    team_id: Optional[int] = Field(default=None, foreign_key="team.id")
    team: Optional[Team] = Relationship(back_populates="heroes")


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def create_heroes():
    with Session(engine) as session:
        team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
        team_z_force = Team(name="Z-Force", headquarters="Sister Margaret’s Bar")

        hero_deadpond = Hero(
            name="Deadpond", secret_name="Dive Wilson", team=team_z_force
        )
        hero_rusty_man = Hero(
            name="Rusty-Man", secret_name="Tommy Sharp", age=48, team=team_preventers
        )
        hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
        session.add(hero_deadpond)
        session.add(hero_rusty_man)
        session.add(hero_spider_boy)
        session.commit()

        session.refresh(hero_deadpond)
        session.refresh(hero_rusty_man)
        session.refresh(hero_spider_boy)

        print("Created hero:", hero_deadpond)
        print("Created hero:", hero_rusty_man)
        print("Created hero:", hero_spider_boy)

        hero_spider_boy.team = team_preventers
        session.add(hero_spider_boy)
        session.commit()
        session.refresh(hero_spider_boy)
        print("Updated hero:", hero_spider_boy)

        hero_black_lion = Hero(name="Black Lion", secret_name="Trevor Challa", age=35)
        hero_sure_e = Hero(name="Princess Sure-E", secret_name="Sure-E")
        team_wakaland = Team(
            name="Wakaland",
            headquarters="Wakaland Capital City",
            heroes=[hero_black_lion, hero_sure_e],
        )
        session.add(team_wakaland)
        session.commit()
        session.refresh(team_wakaland)
        print("Team Wakaland:", team_wakaland)

        hero_tarantula = Hero(name="Tarantula", secret_name="Natalia Roman-on", age=32)
        hero_dr_weird = Hero(name="Dr. Weird", secret_name="Steve Weird", age=36)
        hero_cap = Hero(
            name="Captain North America", secret_name="Esteban Rogelios", age=93
        )

        team_preventers.heroes.append(hero_tarantula)
        team_preventers.heroes.append(hero_dr_weird)
        team_preventers.heroes.append(hero_cap)
        session.add(team_preventers)
        session.commit()
        session.refresh(hero_tarantula)
        session.refresh(hero_dr_weird)
        session.refresh(hero_cap)
        print("Preventers new hero:", hero_tarantula)
        print("Preventers new hero:", hero_dr_weird)
        print("Preventers new hero:", hero_cap)


def main():
    create_db_and_tables()
    create_heroes()


if __name__ == "__main__":
    main()

Description

Official Code Example from https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/create-and-update-relationships/#include-relationship-objects-in-the-many-side

Running the code as instructed throws an AttributeError:

2022-05-19 10:57:57,546 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-05-19 10:57:57,546 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("team")
2022-05-19 10:57:57,546 INFO sqlalchemy.engine.Engine [raw sql] ()
2022-05-19 10:57:57,547 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("hero")
2022-05-19 10:57:57,547 INFO sqlalchemy.engine.Engine [raw sql] ()
2022-05-19 10:57:57,547 INFO sqlalchemy.engine.Engine COMMIT
2022-05-19 10:57:57,547 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-05-19 10:57:57,548 INFO sqlalchemy.engine.Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
2022-05-19 10:57:57,548 INFO sqlalchemy.engine.Engine [generated in 0.00006s] ('Deadpond', 'Dive Wilson', None, None)
2022-05-19 10:57:57,548 INFO sqlalchemy.engine.Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
2022-05-19 10:57:57,548 INFO sqlalchemy.engine.Engine [cached since 0.0004535s ago] ('Rusty-Man', 'Tommy Sharp', 48, None)
2022-05-19 10:57:57,549 INFO sqlalchemy.engine.Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
2022-05-19 10:57:57,549 INFO sqlalchemy.engine.Engine [cached since 0.0005178s ago] ('Spider-Boy', 'Pedro Parqueador', None, None)
2022-05-19 10:57:57,549 INFO sqlalchemy.engine.Engine COMMIT
2022-05-19 10:57:57,550 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id 
FROM hero 
WHERE hero.id = ?
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine [generated in 0.00007s] (7,)
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id 
FROM hero 
WHERE hero.id = ?
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine [cached since 0.0005488s ago] (8,)
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id 
FROM hero 
WHERE hero.id = ?
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine [cached since 0.0007544s ago] (9,)
Created hero: name='Deadpond' team_id=None secret_name='Dive Wilson' id=7 age=None
Created hero: name='Rusty-Man' team_id=None secret_name='Tommy Sharp' id=8 age=48
Created hero: name='Spider-Boy' team_id=None secret_name='Pedro Parqueador' id=9 age=None
2022-05-19 10:57:57,551 INFO sqlalchemy.engine.Engine COMMIT
2022-05-19 10:57:57,552 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-05-19 10:57:57,552 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id 
FROM hero 
WHERE hero.id = ?
2022-05-19 10:57:57,552 INFO sqlalchemy.engine.Engine [cached since 0.001206s ago] (9,)
Updated hero: name='Spider-Boy' team_id=None secret_name='Pedro Parqueador' id=9 age=None
2022-05-19 10:57:57,552 INFO sqlalchemy.engine.Engine INSERT INTO team (name, headquarters) VALUES (?, ?)
2022-05-19 10:57:57,552 INFO sqlalchemy.engine.Engine [generated in 0.00006s] ('Wakaland', 'Wakaland Capital City')
2022-05-19 10:57:57,553 INFO sqlalchemy.engine.Engine COMMIT
2022-05-19 10:57:57,553 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-05-19 10:57:57,554 INFO sqlalchemy.engine.Engine SELECT team.id, team.name, team.headquarters 
FROM team 
WHERE team.id = ?
2022-05-19 10:57:57,554 INFO sqlalchemy.engine.Engine [generated in 0.00006s] (3,)
Team Wakaland: name='Wakaland' headquarters='Wakaland Capital City' id=3
2022-05-19 10:57:57,554 INFO sqlalchemy.engine.Engine ROLLBACK
Traceback (most recent call last):
  File "/Users/marcel/test_sqlmodel/test.py", line 104, in <module>
    main()
  File "/Users/marcel/test_sqlmodel/test.py", line 98, in main
    create_heroes()
  File "/Users/marcel/test_sqlmodel/test.py", line 83, in create_heroes
    team_preventers.heroes.append(hero_tarantula)
AttributeError: 'Team' object has no attribute 'heroes'

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.6

Python Version

3.10.4

Additional Context

No response

@mkrd mkrd added the question Further information is requested label May 19, 2022
@mkrd
Copy link
Author

mkrd commented May 19, 2022

@tiangolo I Checked it with python 3.10, 3.9 and 3.8, all throwing the same error. I always use a clean new venv created with poetry, so there are no conflicts with other packages.

The packages that get installed are:

  • typing-extensions (4.2.0)
  • pydantic (1.9.0)
  • sqlalchemy (1.4.36)
  • sqlalchemy2-stubs (0.0.2a22)
  • sqlmodel (0.0.6)

Maybe there are some breaking changes in sqlalchemy or pydantic, so we need to lock down the version requirements more tightly?

@byrman
Copy link
Contributor

byrman commented May 19, 2022

Check #315.

@tiangolo
Copy link
Member

Thanks for the report @mkrd and for the help @byrman!

It seems this was solved by @byrman in #322.

The fix is available in SQLModel 0.0.7 🚀

@github-actions
Copy link

Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
answered question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants