0Pricing
FastAPI Backend Development Bootcamp · Lección

Operaciones CRUD con SQLAlchemy

Implemente operaciones de creación, lectura, actualización y eliminación para los endpoints de su API mediante el ORM de SQLAlchemy.

Operaciones CRUD con SQLAlchemy es una lección gratuita de FastAPI Backend Development Bootcamp en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de FastAPI Backend Development Bootcamp, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de FastAPI Backend Development Bootcamp incluye 4 lecciones en total.

Partes de esta lección aún no han sido traducidas y se muestran en inglés.

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 = True

Database 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_todo

The 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 todo

We 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_todo

Using 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 204

A 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(), and db.refresh().
  • Read (GET): Using db.query().all() for lists and db.query().filter().first() for single items.
  • Update (PUT): Fetching an item, modifying its attributes, then db.commit() and db.refresh().
  • Delete (DELETE): Fetching an item, then db.delete() and db.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!

Preguntas frecuentes

¿La lección «Operaciones CRUD con SQLAlchemy» es gratis?

Sí — el texto completo de «Operaciones CRUD con SQLAlchemy» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de FastAPI Backend Development Bootcamp, actualiza a CoddyKit PRO. El curso de FastAPI Backend Development Bootcamp incluye 4 lecciones en total.

¿Qué aprenderé en «Operaciones CRUD con SQLAlchemy»?

Implemente operaciones de creación, lectura, actualización y eliminación para los endpoints de su API mediante el ORM de SQLAlchemy. Practicas FastAPI Backend Development Bootcamp con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar FastAPI Backend Development Bootcamp?

No se requiere experiencia previa. FastAPI Backend Development Bootcamp en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Operaciones CRUD con SQLAlchemy»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de FastAPI Backend Development Bootcamp?

Sí. Cada lección de FastAPI Backend Development Bootcamp incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Fundamentos del ORM de SQLAlchemy
  2. Conectar FastAPI con PostgreSQL
  3. Operaciones CRUD con SQLAlchemy
  4. Migraciones de bases de datos con Alembic
← Volver a FastAPI Backend Development Bootcamp