Estoy tratando de implementar una relación autorreferencial de muchos a muchos usando declarativo en SQLAlchemy.¿Cómo puedo lograr una relación autorreferencial de varios a varios en el SQLAlchemy ORM haciendo referencia remota al mismo atributo?
La relación representa la amistad entre dos usuarios. En línea encontré (tanto en la documentación como en Google) cómo hacer una relación auto-referencial m2m donde de alguna manera los roles se diferencian. Esto significa que en estas relaciones m2m UserA es, por ejemplo, el jefe de UserB, por lo que lo enumera bajo un atributo 'subordinados' o lo que sea. De la misma manera, UserB lista UserA en 'superiores'.
Esto constituye ningún problema, ya que se puede declarar una backref a la misma mesa de esta manera:
subordinates = relationship('User', backref='superiors')
Así que, por supuesto, el atributo 'superiores' no es explícita dentro de la clase.
De todos modos, aquí está mi problema: ¿y si quiero volver al mismo atributo donde estoy llamando al backref? De esta manera:
friends = relationship('User',
secondary=friendship, #this is the table that breaks the m2m
primaryjoin=id==friendship.c.friend_a_id,
secondaryjoin=id==friendship.c.friend_b_id
backref=??????
)
Esto tiene sentido, ya que si se hace amigo de un B los roles de relación son los mismos, y si invoco amigos B que debe recibir una lista con A en ella. Este es el código problemático en su totalidad:
friendship = Table(
'friendships', Base.metadata,
Column('friend_a_id', Integer, ForeignKey('users.id'), primary_key=True),
Column('friend_b_id', Integer, ForeignKey('users.id'), primary_key=True)
)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
friends = relationship('User',
secondary=friendship,
primaryjoin=id==friendship.c.friend_a_id,
secondaryjoin=id==friendship.c.friend_b_id,
#HELP NEEDED HERE
)
Lo siento si esto es demasiado texto, sólo quiero ser tan explícito como pueda con esto. Parece que no puedo encontrar ningún material de referencia para esto en la web.
Esto parece ser un poco propenso a errores: puede anexar accidentalmente a 'all_friends' y no recibirá ninguna advertencia. ¿Alguna sugerencia? – Halst
También esto permite tener amistades duplicadas con identificadores intercambiados (como '1, 2' y' 2, 1'). Puede poner una restricción de que un ID es mayor que otro, pero luego necesita hacer un seguimiento de qué usuarios pueden agregarse al atributo 'friends' de los usuarios. – Halst
viewonly = True no tiene relación con el comportamiento de la colección en Python. Si realmente le preocupa la incorporación a esta colección, puede usar collection_cls y aplicar una lista o un tipo de conjunto que tenga los métodos de mutación anulados para arrojar un NotImplementedError o similar. – zzzeek