ποΈ Deleting a Todo (DELETE Request)
In this session, we implement the final CRUD operation:
β Delete β removing an existing record using the DELETE HTTP method
This will permanently remove a Todo from the database.
ποΈ Step 1: Create the DELETE Endpoint
Add this below your existing routes:
ποΈ main.py
@app.delete("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_todo(
db: db_dependency,
todo_id: int = Path(gt=0)):What This Endpoint Does
Receives
todo_idfrom the URLValidates it must be greater than 0
Deletes the matching record
Returns 204 No Content on success
π Step 2: Retrieve the Existing Todo
Before deleting, we must check if the record exists.
ποΈ main.py
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()Why we use .first():
Returns the first matching record
Returns
Noneif no record existsPrevents accidental deletion attempts
β Step 3: Handle Missing Records
If the Todo does not exist:
ποΈ main.py
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")This keeps our API predictable and REST-compliant.
ποΈ Step 4: Delete the Record
Now we delete the object.
β Recommended Approach (Cleaner & Safer)
ποΈ main.py
db.delete(todo_model)
db.commit()
Why This Is Better
Instead of calling:
ποΈ main.py
db.query(Todos).filter(...).delete()Using:
ποΈ main.py
db.delete(todo_model)Operates on the tracked object
Keeps behavior consistent with how SQLAlchemy manages state
Aligns with how we handled UPDATE
π§ Backend Concept: What Happens Internally?
When you call:
ποΈ main.py
db.delete(todo_model)SQLAlchemy:
Marks the object for deletion in the session
Prepares a SQL
DELETEstatementExecutes it when
commit()is called
Without commit(), nothing is removed.
π§© Final Clean Implementation
ποΈ main.py
@app.delete("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_todo(
db: db_dependency,
todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")
db.delete(todo_model)
db.commit()π§ͺ Testing the DELETE Endpoint
Run your server:
uvicorn main:app --reloadThen open:
/docsYou should now see:
GET
/GET
/todo/{todo_id}POST
/todoPUT
/todo/{todo_id}DELETE
/todo/{todo_id}
π Test Scenarios
1οΈβ£ Delete existing ID β 204 No Content
2οΈβ£ Delete non-existing ID β 404 Not Found
3οΈβ£ Use negative ID β 422 Validation Error
ποΈ main.py
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import FastAPI, Path, Depends, HTTPException
from starlette import status
import models
from models import Todos
from database import engine, SessionLocal
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
class TodoRequest(BaseModel):
title: str = Field(min_length=3)
description: str = Field(min_length=3, max_length=100)
priority: int = Field(gt=0, lt=6)
complete: bool
@app.get("/", status_code=status.HTTP_200_OK)
async def read_all(db: db_dependency):
return db.query(Todos).all()
@app.get("/todo/{todo_id}", status_code=status.HTTP_200_OK)
async def read_todo(db: db_dependency, todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is not None:
return todo_model
else:
raise HTTPException(status_code=404, detail='Todo Not Found')
@app.post("/todo/", status_code=status.HTTP_201_CREATED)
async def create_todo(db: db_dependency, todo_request: TodoRequest):
todo_model = Todos(**todo_request.model_dump())
db.add(todo_model)
db.commit()
@app.put("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def update_todo(
db: db_dependency,
todo_request: TodoRequest,
todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")
todo_model.title = todo_request.title
todo_model.description = todo_request.description
todo_model.priority = todo_request.priority
todo_model.complete = todo_request.complete
db.commit()
@app.delete("/todo/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_todo(
db: db_dependency,
todo_id: int = Path(gt=0)):
todo_model = db.query(Todos).filter(Todos.id == todo_id).first()
if todo_model is None:
raise HTTPException(status_code=404, detail="Todo not found.")
db.delete(todo_model)
db.commit()
No Changes in models.py and database.py