Update object with one to many relation SQLAlchemy

Question:

I have User and Item objects:

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)

    items = relationship("Item", back_populates="owner")


class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    owner_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    owner = relationship("User", back_populates="items")

And I have saved in database:

users:
id | email
1  | [email protected]

items:
id | owner_id | title
1  | 1        | aaa
2  | 1        | bbb
3  | NULL     | ccc

Now I would like to update this, so:

def update_user(db: Session, user_id: int, data: dict):
    # data = {"email": "[email protected]", "items": ["1", "3"]}

    db_user = db.query(models.User).filter(models.User.id == user_id).first()

    db_user.email = data["email"]

    // now is the problem:
    db_user.items = data["items"]


    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

This of course not working, because I have array of IDs, not array of object. Is there any simple solution for this? Should I remove all items and next add new to database (mapped to Item objects)? This seems pointless to me, because I would be unnecessarily deleting ID: 1 now, which will later be added again, only it will have a different ID. Maybe there is a trick in SQLAlchemy for this?

Asked By: weskyen

||

Answers:

The simplest solution is to query the database for for the items corresponding to the ids, and then assign them to the user:

# Convert the string ids to integers.
ids = [int(id_) for id_ in data['items']]
items = db.query(Item).filter(Item.id.in_(ids)).all()
db_user.items = items
Answered By: snakecharmerb
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.