Relaciones¶
class Post(Table):
__tablename__ = 'post'
id: col[int] = column(primary_key=True, autoincrement=True)
titulo: col[str]
autor_id: col[int] # la columna FK, declarada a mano
autor: manytoone[Autor] = relation(
fields=['autor_id'], # columnas de ESTA tabla
references=['id'], # columnas de la tabla destino
backref='posts', # cómo se llama el lado inverso
onDelete='cascade', # 'cascade' | 'set null' | 'restrict'
onUpdate='cascade',
)
Los tres primeros argumentos (fields, references, backref) son obligatorios.
relation() se declara solo en la tabla que posee las columnas FK
Es la regla que más se incumple. El otro lado es implícito:
Las tres cardinalidades¶
class Autor(Table):
__tablename__ = 'autor'
id: col[int] = column(primary_key=True, autoincrement=True)
nombre: col[str]
posts: onetomany[Post] # lado implícito
class Post(Table):
__tablename__ = 'post'
id: col[int] = column(primary_key=True, autoincrement=True)
autor_id: col[int]
autor: manytoone[Autor] = relation(
fields=['autor_id'], references=['id'], backref='posts'
)
class Usuario(Table):
__tablename__ = 'usuario'
id: col[int] = column(primary_key=True, autoincrement=True)
perfil: onetoone[Perfil]
class Perfil(Table):
__tablename__ = 'perfil'
id: col[int] = column(primary_key=True, autoincrement=True)
usuario_id: col[int] = column(unique=True) # la unicidad es lo que lo hace 1:1
usuario: onetoone[Usuario] = relation(
fields=['usuario_id'], references=['id'], backref='perfil'
)
La sintaxis v1 no sabe expresar un uno a uno: un hint escalar se interpreta siempre como many-to-one.
No hay una declaración especial: se modela con la tabla intermedia, que es lo que existe de verdad en la base de datos.
class UsuarioRol(Table):
__tablename__ = 'usuario_rol'
__constraints__ = unique_constraint('usuario_id', 'rol_id')
id: col[int] = column(primary_key=True, autoincrement=True)
usuario_id: col[int]
rol_id: col[int]
usuario: manytoone[Usuario] = relation(
fields=['usuario_id'], references=['id'], backref='roles'
)
rol: manytoone[Rol] = relation(
fields=['rol_id'], references=['id'], backref='usuarios'
)
Claves compuestas¶
fields y references son listas porque una FK puede abarcar varias columnas:
linea: manytoone[LineaPedido] = relation(
fields=['pedido_id', 'linea_num'],
references=['pedido_id', 'num'],
backref='envios',
)
Qué pasa con onDelete y onUpdate¶
Se traducen a las cláusulas ON DELETE / ON UPDATE de la clave foránea, y por tanto las
impone la base de datos, no el cliente generado.
| Valor | Efecto al borrar la fila referenciada |
|---|---|
'cascade' (por defecto) |
Borra también las filas que la referencian |
'set null' |
Pone la FK a NULL (la columna tiene que ser opcional) |
'restrict' |
Impide el borrado |
Límites¶
- Las relaciones entre schemas distintos no se declaran. Son dos bases de datos lógicas separadas; si lo intentas, el análisis lo dice (E003: «apunta a X, que no está declarado en este schema»).
- Una constraint no se declara sobre el nombre de una relación, sino sobre las columnas
físicas:
usuario_id, nousuario. - Para cargar relaciones al consultar, ver
includes.