Opérations CRUD avec SQLAlchemy
Implémentez les opérations de création, de lecture, de mise à jour et de suppression pour vos points d’accès d’API avec l’ORM SQLAlchemy.
Opérations CRUD avec SQLAlchemy est une leçon FastAPI Backend Development Bootcamp gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage FastAPI Backend Development Bootcamp, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours FastAPI Backend Development Bootcamp comprend 4 leçons au total.
Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.
CRUD Operations: The Core
Welcome to Lesson 3! Today, we'll master CRUD operations using FastAPI and SQLAlchemy. CRUD stands for:
- Create: Adding new data.
- Read: Retrieving existing data.
- Update: Modifying existing data.
- Delete: Removing data.
These four operations are the foundation of almost any application that interacts with a database.
Setup: Models & Session
Before diving into CRUD, let's set up our SQLAlchemy model and Pydantic schemas. We'll use an in-memory SQLite database for our runnable examples.
First, our SQLAlchemy Todo model to represent a task:
from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, default="")
completed = Column(Boolean, default=False)And Pydantic schemas for request/response:
from pydantic import BaseModel
class TodoCreate(BaseModel):
title: str
description: str = ""
completed: bool = False
class TodoResponse(TodoCreate):
id: int
class Config:
orm_mode = TrueDatabase Session in FastAPI
In FastAPI, we manage database sessions using dependencies. This ensures each request gets a fresh session and it's properly closed.
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()This get_db function will be injected into our FastAPI endpoints.
Create: FastAPI Endpoint
To Create a new item, we'll use a POST request. The endpoint will receive data via a Pydantic model and use SQLAlchemy to add it to the database.
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
# ... (imports for Base, Todo, TodoCreate, TodoResponse, get_db, engine)
app = FastAPI()
Base.metadata.create_all(bind=engine) # Create tables
@app.post("/todos/", response_model=TodoResponse)
def create_todo(todo: TodoCreate, db: Session = Depends(get_db)):
db_todo = Todo(title=todo.title, description=todo.description, completed=todo.completed)
db.add(db_todo)
db.commit()
db.refresh(db_todo) # Refresh to get ID and updated fields
return db_todoThe db.refresh() call updates our db_todo object with any database-generated values, like the id.
Create: SQLAlchemy Demo
Let's see the SQLAlchemy 'Create' steps in action. This runnable script will add a new todo to our in-memory database.
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 1. Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, default="")
completed = Column(Boolean, default=False)
# 2. Create Tables
Base.metadata.create_all(bind=engine)
# 3. Create a Session
db = SessionLocal()
# 4. Create Operation (C)
print("--- Creating a new Todo ---")
new_todo = Todo(title="Learn FastAPI", description="Complete CoddyKit lesson", completed=False)
db.add(new_todo)
db.commit()
db.refresh(new_todo)
print(f"Created Todo: ID={new_todo.id}, Title='{new_todo.title}'")
# 5. Close Session
db.close()Read: FastAPI Endpoints
To Read data, we use GET requests. We'll have two endpoints: one to get all todos, and another to get a single todo by its ID.
# ... (FastAPI app, imports, get_db, models)
@app.get("/todos/", response_model=list[TodoResponse])
def read_todos(db: Session = Depends(get_db)):
todos = db.query(Todo).all()
return todos
@app.get("/todos/{todo_id}", response_model=TodoResponse)
def read_todo(todo_id: int, db: Session = Depends(get_db)):
todo = db.query(Todo).filter(Todo.id == todo_id).first()
if todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return todoWe use .all() to get a list and .first() to get a single item. Remember to handle cases where an item isn't found!
Read: SQLAlchemy Demo
Let's run a demo for the 'Read' operation. We'll first create a few todos, then fetch them all, and finally fetch a specific one by ID.
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Setup Database and Model (same as before)
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, default="")
completed = Column(Boolean, default=False)
Base.metadata.create_all(bind=engine)
db = SessionLocal()
# Create some initial Todos for reading
todo1 = Todo(title="Buy groceries")
todo2 = Todo(title="Walk the dog")
db.add_all([todo1, todo2])
db.commit()
db.refresh(todo1)
db.refresh(todo2)
print(f"Created Todos: {todo1.id}, {todo2.id}\n")
# Read Operation (R)
print("--- Reading all Todos ---")
all_todos = db.query(Todo).all()
for t in all_todos:
print(f"ID={t.id}, Title='{t.title}'")
print("\n--- Reading a specific Todo (ID 1) ---")
specific_todo = db.query(Todo).filter(Todo.id == 1).first()
if specific_todo:
print(f"Found Todo: ID={specific_todo.id}, Title='{specific_todo.title}'")
else:
print("Todo with ID 1 not found.")
print("\n--- Reading a non-existent Todo (ID 99) ---")
non_existent_todo = db.query(Todo).filter(Todo.id == 99).first()
if non_existent_todo:
print(f"Found Todo: ID={non_existent_todo.id}")
else:
print("Todo with ID 99 not found.")
db.close()Update: FastAPI Endpoint
The Update operation (PUT or PATCH) allows us to modify an existing item. We'll typically find the item by ID, update its attributes, and commit the changes.
# ... (FastAPI app, imports, get_db, models)
class TodoUpdate(BaseModel):
title: str | None = None
description: str | None = None
completed: bool | None = None
@app.put("/todos/{todo_id}", response_model=TodoResponse)
def update_todo(todo_id: int, todo_update: TodoUpdate, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if db_todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
# Update fields only if provided
for key, value in todo_update.dict(exclude_unset=True).items():
setattr(db_todo, key, value)
db.add(db_todo) # Re-add to session for update tracking
db.commit()
db.refresh(db_todo)
return db_todoUsing exclude_unset=True in Pydantic ensures only provided fields are updated.
Update: SQLAlchemy Demo
Here's a runnable example showing how to update a todo item's title and completion status using SQLAlchemy.
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, default="")
completed = Column(Boolean, default=False)
Base.metadata.create_all(bind=engine)
db = SessionLocal()
# Create an initial Todo to update
initial_todo = Todo(title="Draft report", completed=False)
db.add(initial_todo)
db.commit()
db.refresh(initial_todo)
print(f"Created Todo: ID={initial_todo.id}, Title='{initial_todo.title}', Completed={initial_todo.completed}\n")
# Update Operation (U)
print(f"--- Updating Todo ID {initial_todo.id} ---")
todo_to_update = db.query(Todo).filter(Todo.id == initial_todo.id).first()
if todo_to_update:
todo_to_update.title = "Finalize report"
todo_to_update.completed = True
db.commit()
db.refresh(todo_to_update)
print(f"Updated Todo: ID={todo_to_update.id}, Title='{todo_to_update.title}', Completed={todo_to_update.completed}")
else:
print(f"Todo with ID {initial_todo.id} not found.")
db.close()Delete: FastAPI Endpoint
The Delete operation removes an item from the database. This is usually done with a DELETE request, targeting an item by its ID.
# ... (FastAPI app, imports, get_db, models)
@app.delete("/todos/{todo_id}", status_code=204) # 204 No Content for successful deletion
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if db_todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
db.delete(db_todo)
db.commit()
return {"message": "Todo deleted successfully"} # FastAPI automatically handles 204A successful deletion often returns a 204 No Content status code, meaning the request was fulfilled but there's no content to send back.
Delete: SQLAlchemy Demo
Let's run a script to demonstrate deleting a todo item. We'll create one, then delete it, and try to read it again to confirm its removal.
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Setup Database and Model
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, default="")
completed = Column(Boolean, default=False)
Base.metadata.create_all(bind=engine)
db = SessionLocal()
# Create an initial Todo to delete
todo_to_delete = Todo(title="Clean garage")
db.add(todo_to_delete)
db.commit()
db.refresh(todo_to_delete)
print(f"Created Todo: ID={todo_to_delete.id}, Title='{todo_to_delete.title}'\n")
# Delete Operation (D)
print(f"--- Deleting Todo ID {todo_to_delete.id} ---")
db.delete(todo_to_delete)
db.commit()
print(f"Todo ID {todo_to_delete.id} deleted.\n")
# Verify deletion by trying to read it
print("--- Verifying deletion ---")
verify_deleted = db.query(Todo).filter(Todo.id == todo_to_delete.id).first()
if verify_deleted is None:
print(f"Successfully verified: Todo ID {todo_to_delete.id} is no longer in the database.")
else:
print(f"Error: Todo ID {todo_to_delete.id} still found.")
db.close()CRUD Challenge
You've learned the core CRUD operations! Now, let's test your understanding of how SQLAlchemy methods map to these operations.
Recap & Next Steps
Great job! In this lesson, you've learned to implement the fundamental CRUD operations in FastAPI using SQLAlchemy:
- Create (POST): Using
db.add(),db.commit(), anddb.refresh(). - Read (GET): Using
db.query().all()for lists anddb.query().filter().first()for single items. - Update (PUT): Fetching an item, modifying its attributes, then
db.commit()anddb.refresh(). - Delete (DELETE): Fetching an item, then
db.delete()anddb.commit().
These skills are crucial for building any data-driven API. In the next course, we'll dive into advanced topics like user authentication and authorization to secure your API endpoints!
Questions Fréquemment Posées
La leçon « Opérations CRUD avec SQLAlchemy » est-elle gratuite ?
Oui — le texte complet de « Opérations CRUD avec SQLAlchemy » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours FastAPI Backend Development Bootcamp, passe à CoddyKit PRO. Le cours FastAPI Backend Development Bootcamp comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Opérations CRUD avec SQLAlchemy » ?
Implémentez les opérations de création, de lecture, de mise à jour et de suppression pour vos points d’accès d’API avec l’ORM SQLAlchemy. Tu pratiques FastAPI Backend Development Bootcamp avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer FastAPI Backend Development Bootcamp ?
Aucune expérience préalable n'est requise. FastAPI Backend Development Bootcamp sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Opérations CRUD avec SQLAlchemy » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon FastAPI Backend Development Bootcamp ?
Oui. Chaque leçon FastAPI Backend Development Bootcamp inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Fondamentaux de l’ORM SQLAlchemy
- Connecter FastAPI à PostgreSQL
- Opérations CRUD avec SQLAlchemy
- Migrations de base de données avec Alembic