Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

FastAPI: Update whole row with put (by either id or a unique name)

this seems super basic but I just CANNOT get it to work after hours, feeling super dumb.

I have a SQLite DB with a table called players that each have an id (int), a name (str) and an is_active (bool) attribute.
Making a get endpoint to get all of the entries was no problem.
I now want an endpoint that can update a row via put. It does not have to be patch since all attributes to update are provided.

The models

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class PlayerBase(BaseModel):
    name: str
    active: bool

class PlayerModel(PlayerBase):
    id: int

    class Config:
        from_attributes = True

The working endpoints

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


db_dependency = Annotated[Session, Depends(get_db)]

models.Base.metadata.create_all(bind=engine)

@app.post("/players/", response_model=PlayerModel)
async def create_player(player: PlayerBase, db: db_dependency):
    db_player = models.Player(**player.dict())
    db.add(db_player)
    db.commit()
    db.refresh(db_player)
    return db_player


@app.get("/players/", response_model=List[PlayerModel])
async def read_players(db: db_dependency, skip: int = 0, limit: int = 100):
    players = db.query(models.Player).offset(skip).limit(limit).all()
    return players

Now, how do I achieve what I want? I have tried 100 different things producing 200 different errors, so I don’t think it even makes sense to tell you guys what I’ve tried since I’m just completely confused now.
One thing I wanted was to get a player by it’s id as an intermediate step (and because it’s just nice to have), but this just super didn’t work despite being seemingly very close to the other get that does work.

@app.get("/players/{player_id}", response_model=PlayerModel)
async def read_player(db: db_dependency, player_id: int):
    player = db.query(models.Player).filter_by(id = player_id)
    return player

For context, in a React app I have a field where one can enter a name and click a checkbox for if the player is active or not. That then gets posted and created a new entry. Works great. I now want to update the active field if an existing player is entered with a different state in is_active. Does not work at all, see above.

Would appreciate any help A LOT!

>Solution :

I see where the confusion might be stemming from.

  1. Fetching a player by ID:
    The issue with your read_player function is that after filtering the query by the player’s ID, you never actually execute the query to fetch the data. This is why it doesn’t work. You need to add .first() at the end of the query to get the first record that matches the criteria.

    @app.get("/players/{player_id}", response_model=PlayerModel)
    async def read_player(db: db_dependency, player_id: int):
        player = db.query(models.Player).filter_by(id=player_id).first()
        if player is None:
            raise HTTPException(status_code=404, detail="Player not found")
        return player
    
  2. Updating a player:
    To update a player, you need a PUT endpoint that takes in the player’s ID and the new data to update. Here’s how you can implement this:

    @app.put("/players/{player_id}", response_model=PlayerModel)
    async def update_player(player_id: int, player_data: PlayerBase, db: db_dependency):
        # Fetch the player you want to update
        player = db.query(models.Player).filter_by(id=player_id).first()
        if player is None:
            raise HTTPException(status_code=404, detail="Player not found")
    
        # Update the player's data
        for key, value in player_data.dict().items():
            setattr(player, key, value)
    
        db.commit()
        db.refresh(player)
        return player
    
  3. React Side:
    On the React side, when you want to update a player’s data, you’ll make a PUT request to the /players/{player_id} endpoint with the updated data. If a player with the entered name exists, you’ll update the active field using this endpoint.

In the code above, I used the filter_by method for the query, which is just one way to filter the records. You can also use the filter method and provide conditions in a slightly different manner, e.g., filter(models.Player.id == player_id). Both methods are valid and achieve the same result; it’s a matter of personal preference.

With these changes, your update functionality should work as expected.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading