python - practices - SQLAlchemy Relación muchos a muchos en una sola tabla
sqlalchemy models (2)
Tengo un modelo SQLAlchemy configurado en mi aplicación que debe imitar la funcionalidad de "seguidores" en Twitter, es decir. los usuarios tienen una relación de muchos a muchos entre sí (seguidores y seguidores). Las tablas están estructuradas de la siguiente manera (sa es el módulo sqlalchemy):
t_users = sa.Table("users", meta.metadata,
sa.Column("id", sa.types.Integer, primary_key=True),
sa.Column("email", sa.types.String(320), unique=True, nullable=False),
...etc...
)
t_follows = sa.Table("follows", meta.metadata,
sa.Column("id", sa.types.Integer, primary_key=True),
sa.Column("follower_id", sa.types.Integer, sa.ForeignKey(''users.id''), nullable=False),
sa.Column("followee_id", sa.types.Integer, sa.ForeignKey(''users.id''), nullable=False)
)
Sin embargo, me encontré con una especie de obstáculo al intentar utilizar orm.mapper para crear esta relación, ya que la tabla secundaria hace referencia a la misma tabla principal en ambas direcciones. ¿Cómo haría para mapear esta relación con el ORM?
En este caso, debe escribir secondaryjoin
condiciones de primaryjoin
y secondaryjoin
explícitamente:
mapper(
User, t_users,
properties={
''followers'': relation(
User,
secondary=t_follows,
primaryjoin=(t_follows.c.followee_id==t_users.c.id),
secondaryjoin=(t_follows.c.follower_id==t_users.c.id),
),
''followees'': relation(
User,
secondary=t_follows,
primaryjoin=(t_follows.c.follower_id==t_users.c.id),
secondaryjoin=(t_follows.c.followee_id==t_users.c.id),
),
},
)
He escrito este ejemplo detallado para ayudarlo a comprender mejor lo que primaryjoin
secondaryjoin
parámetros primaryjoin
y secondaryjoin
. Claro, puedes hacer que backref
con backref
.
Por cierto, no necesita la columna de id
en la tabla siguiente, use en su lugar la clave primaria compuesta. De hecho, debe definir una restricción única de follower_id
y followee_id
pair de todos modos (ya sea como clave única primaria o adicional).
También puedes hacer esto de manera declarativa.
Aquí hay un ejemplo similar basado en el código anterior, yo uso el backref.
VolumeRelationship = Table(
''VolumeRelationship'', Base.metadata,
Column(''ParentID'', Integer, ForeignKey(''Volumes.ID'')),
Column(''VolumeID'', Integer, ForeignKey(''Volumes.ID''))
)
class Volume(Base):
""" Volume Object """
__tablename__ = "Volumes"
id = Column(''ID'', Integer, primary_key=True, nullable=False)
type = Column(''Type'', String(25))
name = Column(''Name'', String(25))
poolid = Column(''pool'', Integer, ForeignKey(''Pools.ID''))
parents = relation(
''Volume'',secondary=VolumeRelationship,
primaryjoin=VolumeRelationship.c.VolumeID==id,
secondaryjoin=VolumeRelationship.c.ParentID==id,
backref="children")