Objetivos de Aprendizaje
Al finalizar esta clase, seras capaz de:
- Entender que es un ORM (Object Relational Mapper)
- Configurar SQLAlchemy con SQLite
- Crear modelos con
DeclarativeBase - Definir columnas con tipos de datos
- Crear tablas desde modelos
Video Recomendado
Curso completo de SQLAlchemy ORM:
Ver Playlist "SQLAlchemy ORM Tutorial" 6 videos | Jerin Jose¿Qué es un ORM? (10 min)
ORM (Object-Relational Mapping / Mapeo Objeto-Relacional) es una técnica que permite mapear objetos de programación a tablas de una base de datos relacional, evitando escribir SQL (Structured Query Language / Lenguaje de Consulta Estructurado) manualmente para las operaciones comunes.
Ventajas del ORM:
- Escribes Python, no SQL
- Codigo portable entre bases de datos
- Autocompletado y type hints
- Relaciones como atributos de objetos
Comparacion
# Sin ORM (SQL directo)
cursor.execute("""
INSERT INTO usuarios (username, email)
VALUES (?, ?)
""", ("juan", "juan@test.com"))
# Con ORM (Python)
usuario = Usuario(username="juan", email="juan@test.com")
session.add(usuario)
session.commit()
Configuracion (15 min)
Instalacion
pip install sqlalchemy
Configuracion Base
# database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
# Engine: conexion a la base de datos
engine = create_engine("sqlite:///taskflow.db", echo=True)
# SessionLocal: fabrica de sesiones
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
# Base: clase base para todos los modelos
class Base(DeclarativeBase):
pass
# Dependencia para FastAPI
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# Crear todas las tablas
def crear_tablas():
Base.metadata.create_all(bind=engine)
Tip:
echo=True muestra el SQL generado. Desactivalo en produccion.
Crear Modelos (25 min)
Modelo Usuario
# models/usuario.py
from sqlalchemy import String, Boolean, DateTime
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from typing import Optional, List
from database import Base
class Usuario(Base):
__tablename__ = "usuarios"
# Columnas
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False)
email: Mapped[str] = mapped_column(String(100), unique=True, nullable=False)
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
activo: Mapped[bool] = mapped_column(Boolean, default=True)
creado_en: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
# Relaciones
proyectos: Mapped[List["Proyecto"]] = relationship(back_populates="usuario")
def __repr__(self):
return f""
Modelo Proyecto
# models/proyecto.py
from sqlalchemy import String, ForeignKey, DateTime
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from typing import Optional, List
from database import Base
class Proyecto(Base):
__tablename__ = "proyectos"
id: Mapped[int] = mapped_column(primary_key=True)
nombre: Mapped[str] = mapped_column(String(100), nullable=False)
descripcion: Mapped[Optional[str]] = mapped_column(String(500))
usuario_id: Mapped[int] = mapped_column(ForeignKey("usuarios.id"))
creado_en: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
# Relaciones
usuario: Mapped["Usuario"] = relationship(back_populates="proyectos")
tareas: Mapped[List["Tarea"]] = relationship(back_populates="proyecto")
def __repr__(self):
return f""
Modelo Tarea
# models/tarea.py
from sqlalchemy import String, Boolean, ForeignKey, DateTime, Enum
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from enum import Enum as PyEnum
from typing import Optional
from database import Base
class EstadoTarea(PyEnum):
PENDIENTE = "pendiente"
EN_PROGRESO = "en_progreso"
COMPLETADA = "completada"
class Prioridad(PyEnum):
BAJA = "baja"
MEDIA = "media"
ALTA = "alta"
URGENTE = "urgente"
class Tarea(Base):
__tablename__ = "tareas"
id: Mapped[int] = mapped_column(primary_key=True)
titulo: Mapped[str] = mapped_column(String(200), nullable=False)
descripcion: Mapped[Optional[str]] = mapped_column(String(1000))
completada: Mapped[bool] = mapped_column(Boolean, default=False)
prioridad: Mapped[Prioridad] = mapped_column(Enum(Prioridad), default=Prioridad.MEDIA)
estado: Mapped[EstadoTarea] = mapped_column(Enum(EstadoTarea), default=EstadoTarea.PENDIENTE)
proyecto_id: Mapped[int] = mapped_column(ForeignKey("proyectos.id"))
creado_en: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
# Relaciones
proyecto: Mapped["Proyecto"] = relationship(back_populates="tareas")
def __repr__(self):
return f""
Ejercicio: Crear Tablas (15 min)
# main.py
from database import engine, Base, crear_tablas
from models.usuario import Usuario
from models.proyecto import Proyecto
from models.tarea import Tarea
# Crear tablas
if __name__ == "__main__":
print("Creando tablas...")
crear_tablas()
print("Tablas creadas exitosamente!")
# Verificar
from sqlalchemy import inspect
inspector = inspect(engine)
tablas = inspector.get_table_names()
print(f"Tablas en la base de datos: {tablas}")
E4 Laboratorio: Crea un modelo Comentario con relacion a Tarea.
Resumen
- ORM: Mapea objetos Python a tablas SQL
- DeclarativeBase: Clase base para modelos
- Mapped[T]: Type hint para columnas
- mapped_column(): Define propiedades de columna
- relationship(): Define relaciones entre tablas
- ForeignKey: Clave foranea