question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to modify values of many to many relationship in the crud interface

See original GitHub issue

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 FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” 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 FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.
  • After submitting this, I commit to one of:
    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
    • I already hit the “watch” button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
    • Implement a Pull Request for a confirmed bug.

Hello everyone. I am having a really hard time updating a user with a many to many relationship. The models used are these.

class UserBase(BaseModel):
    email: Optional[EmailStr] = None
    is_active: Optional[bool] = True
    is_superuser: bool = False
    full_name: Optional[str] = None
    roles: List[Role] = []

class User(Base):
    id = Column(Integer, primary_key=True, index=True)
    full_name = Column(String, index=True)
    email = Column(String, unique=True, index=True, nullable=False)
    hashed_password = Column(String, nullable=False)
    is_active = Column(Boolean(), default=True)
    is_superuser = Column(Boolean(), default=False)
    items = relationship("Item", back_populates="owner")
    roles = relationship(
        'Role', secondary=user_role,
        backref=backref("users")
    )

All the models have Config orm=True

The usage is that I have an admin panel where I can add roles to a profile. So I get the json model to the Vue app, add new roles and then post it to the api. When this updated model tries to set the roles attribute it fails.

Now after the endpoint is called. I see the new roles in the pydantic model as expected. But when the crud update tries to apply the new roles in the list it fails.

But when it reaches this point

    def update(
        self,
        db: Session,
        *,
        db_obj: ModelType,
        obj_in: Union[UpdateSchemaType, Dict[str, Any]]
    ) -> ModelType:
        obj_data = jsonable_encoder(db_obj)
        if isinstance(obj_in, dict):
            update_data = obj_in
        else:
            update_data = obj_in.dict(exclude_unset=True)
        for field in obj_data:
            if field in update_data:
                setattr(db_obj, field, update_data[field]) <------- Fails here
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj

When I try to update user profile and add more roles to the list. I get the following error. backend_1 | File “/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py”, line 45, in append backend_1 | item_state = attributes.instance_state(item) backend_1 | AttributeError: ‘dict’ object has no attribute ‘_sa_instance_state’

Any idea what I can be doing incorrectly ? Using fastapi = “^0.60.1” and Python 3.8 Thanks

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:6

github_iconTop GitHub Comments

3reactions
amirjanicommented, Oct 29, 2020

Hi,

after looking at SQLAlchemy I realized that for having many to many relations like user_role we should do something like below code:

"""
file: user.py
"""
class User(Base):
    __tablename__ = "user"

    id = Column(Integer, primary_key=True, index=True)
    full_name = Column(String, index=True)
    email = Column(String, unique=True, index=True, nullable=False)
    hashed_password = Column(String, nullable=False)
    is_active = Column(Boolean(), default=True)
    is_superuser = Column(Boolean(), default=False)

    items = relationship("Role", secondary=UserRole.__tablename__, back_populates="user")
"""
file: role.py
"""
class Role(Base):
    __tablename__ = 'role'

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    is_primary = Column(Boolean)

    items = relationship("User", secondary=UserRole.__tablename__, back_populates="role")
"""
file: user_role.py
"""
class UserRole(Base):
    __tablename__ = 'user_role'

    user_id = Column('user_id', ForeignKey('user.id'), primary_key=True)
    role_id = Column('role_id', ForeignKey('role.id'), primary_key=True)

don’t forget to import UserRole class in User and Role classes

1reaction
Silurcommented, Mar 15, 2021

the problem is that jsonable_encoder returns an empty object {} when called on a model that contains a many-to-many relationship, thus you cannot use inherited functions from crud/base.py

Read more comments on GitHub >

github_iconTop Results From Across the Web

php - How to implement CRUD with many:many relationship
Question is, how you define Models. One solution is, as you already explained yourself, with 3 models. But you can also do something...
Read more >
CRUD operations explained: Create, read, update, and delete
CRUD operations are used to manipulate, read, insert, delete, ... we want to add multiple rows, we do that using: INSERT INTO menu....
Read more >
CRUD Many-to-Many Entity Framework - CodeProject
First, when data do not exist in tables, add instances to context, add an instance to navigation property and call SaveChanges method from ......
Read more >
Update and Remove Many-to-Many Relationships - SQLModel
Now we'll see how to update and remove these many-to-many relationships. We'll continue from where we left off with the previous code. Full...
Read more >
How To Use Many-to-Many Database Relationships with ...
A many-to-many relationship links two tables where each item in a table has many related items in the other table. In the association...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found