Objetivos de Aprendizaje
Al finalizar esta clase, seras capaz de:
- Crear relaciones Uno a Muchos (One-to-Many)
- Crear relaciones Muchos a Uno (Many-to-One)
- Usar
relationship()yForeignKey - Navegar relaciones como atributos
- Configurar
back_populates
Relacion Uno a Muchos (20 min)
Un Usuario tiene muchos Proyectos.
# models/usuario.py
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from typing import List
class Usuario(Base):
__tablename__ = "usuarios"
id: Mapped[int] = mapped_column(primary_key=True)
username: Mapped[str] = mapped_column(String(50), unique=True)
# RELACION: Un usuario tiene muchos proyectos
proyectos: Mapped[List["Proyecto"]] = relationship(
back_populates="usuario",
cascade="all, delete-orphan"
)
cascade="all, delete-orphan": Al eliminar un usuario, se eliminan sus proyectos.
Relacion Muchos a Uno (15 min)
Muchos Proyectos pertenecen a un Usuario.
# models/proyecto.py
from sqlalchemy import String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
class Proyecto(Base):
__tablename__ = "proyectos"
id: Mapped[int] = mapped_column(primary_key=True)
nombre: Mapped[str] = mapped_column(String(100))
# CLAVE FORANEA: Referencia al usuario
usuario_id: Mapped[int] = mapped_column(ForeignKey("usuarios.id"))
# RELACION: Un proyecto pertenece a un usuario
usuario: Mapped["Usuario"] = relationship(back_populates="proyectos")
Relacion Bidireccional (20 min)
Proyecto tiene muchas Tareas. Tarea pertenece a un Proyecto.
# models/proyecto.py (actualizado)
from typing import List
class Proyecto(Base):
__tablename__ = "proyectos"
id: Mapped[int] = mapped_column(primary_key=True)
nombre: Mapped[str] = mapped_column(String(100))
usuario_id: Mapped[int] = mapped_column(ForeignKey("usuarios.id"))
# Relaciones
usuario: Mapped["Usuario"] = relationship(back_populates="proyectos")
tareas: Mapped[List["Tarea"]] = relationship(back_populates="proyecto")
# models/tarea.py
class Tarea(Base):
__tablename__ = "tareas"
id: Mapped[int] = mapped_column(primary_key=True)
titulo: Mapped[str] = mapped_column(String(200))
proyecto_id: Mapped[int] = mapped_column(ForeignKey("proyectos.id"))
# Relacion
proyecto: Mapped["Proyecto"] = relationship(back_populates="tareas")
Navegar Relaciones
from sqlalchemy.orm import Session
from database import SessionLocal
db: Session = SessionLocal()
# Obtener usuario con sus proyectos
usuario = db.query(Usuario).filter_by(username="juan").first()
# Acceder a proyectos como atributo
for proyecto in usuario.proyectos:
print(f"Proyecto: {proyecto.nombre}")
# Acceder a tareas del proyecto
for tarea in proyecto.tareas:
print(f" - Tarea: {tarea.titulo}")
# Desde una tarea, acceder al proyecto y usuario
tarea = db.query(Tarea).first()
print(f"Tarea: {tarea.titulo}")
print(f"Proyecto: {tarea.proyecto.nombre}")
print(f"Usuario: {tarea.proyecto.usuario.username}")
Ejercicio: Modelo Comentario (20 min)
Crear un modelo Comentario que pertenezca a una Tarea:
# models/comentario.py
from sqlalchemy import String, ForeignKey, DateTime, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
class Comentario(Base):
__tablename__ = "comentarios"
id: Mapped[int] = mapped_column(primary_key=True)
contenido: Mapped[str] = mapped_column(Text, nullable=False)
tarea_id: Mapped[int] = mapped_column(ForeignKey("tareas.id"))
creado_en: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Relacion: Un comentario pertenece a una tarea
tarea: Mapped["Tarea"] = relationship(back_populates="comentarios")
# Actualizar Tarea
class Tarea(Base):
__tablename__ = "tareas"
id: Mapped[int] = mapped_column(primary_key=True)
titulo: Mapped[str] = mapped_column(String(200))
proyecto_id: Mapped[int] = mapped_column(ForeignKey("proyectos.id"))
# Relaciones
proyecto: Mapped["Proyecto"] = relationship(back_populates="tareas")
comentarios: Mapped[List["Comentario"]] = relationship(
back_populates="tarea",
cascade="all, delete-orphan"
)
E4 Laboratorio: Implementa CRUD completo con las relaciones Usuario-Proyecto-Tarea-Comentario.
Resumen
- ForeignKey: Define la columna que referencia otra tabla
- relationship(): Crea la relacion navegable
- back_populates: Conecta relaciones bidireccionales
- cascade: Define comportamiento al eliminar
- List["Modelo"]: Indica relacion uno-a-muchos