SQLAlchemy auto-jointure déclarative many-to-many via un objet Association
J'ai une table des Utilisateurs et d'une table d'Amis qui mappe des utilisateurs à d'autres utilisateurs que chaque utilisateur peut avoir beaucoup d'amis. Cette relation est évidemment symétrique: si l'utilisateur A est un ami de l'utilisateur B, alors l'utilisateur B est aussi un ami de l'utilisateur A, je ne stocker cette relation une fois. Les Amis de la table a des champs supplémentaires outre les deux ID d'Utilisateur j'ai donc utiliser un objet association.
Je suis en train de définir cette relation dans déclaratif de style dans les Utilisateurs de la classe (qui s'étend à l'ensemble des déclarations de la base), mais je n'arrive pas à comprendre comment faire cela. Je veux être en mesure d'accéder à tous les amis d'un utilisateur par l'intermédiaire d'une propriété amis, ce que disent les amis = bob.des amis.
Quelle est la meilleure approche pour résoudre ce problème? J'ai essayé à de nombreuses configurations différentes de la poster ici, et aucun d'entre eux travaillaient pour diverses raisons.
EDIT: Ma dernière tentative ressemble à ceci:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
# Relationships
friends1 = relationship('Friends', primaryjoin=lambda: id==Friends.friend1ID)
friends2 = relationship('Friends', primaryjoin=lambda: id==Friends.friend2ID)
class Friends(Base):
__tablename__ = 'friends'
id = Column(Integer, primary_key=True)
friend1ID = Column(Integer, ForeignKey('users.id') )
friend2ID = Column(Integer, ForeignKey('users.id') )
status = Column(Integer)
# Relationships
vriend1 = relationship('Student', primaryjoin=student2ID==Student.id)
vriend2 = relationship('Student', primaryjoin=student1ID==Student.id)
Cela se traduit cependant l'erreur suivante:
InvalidRequestError: Table 'users' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
Je dois avouer qu'en ce moment je suis complètement confus, parce que de nombreuses tentatives ont échoué et ont fait plus d'une erreur stupide dans le ci-dessus.
source d'informationauteur Janny
Vous devez vous connecter pour publier un commentaire.
Cette exception particulière est causée par la description de la table plus d'une fois, soit en plusieurs reprises de définir le mapping de la classe (par exemple, dans interactive interprète, ou dans une fonction qui peut être appelé plus d'une fois), ou par le mélange de style déclaratif mappages de classe avec tableau de réflexion. Dans le premier cas, d'éliminer les appels répétés; démarrer une nouvelle interprète si vous le faites de manière interactive, ou d'éliminer les extra appels de fonction (peut-être une bonne utilisation pour un singleton/borg objet).
Dans ce dernier cas, il suffit de faire ce que l'exception dit, ajouter
__table_args__ = {'extend_existing': True}
comme un supplément variable de classe dans vos définitions de classe. Faire cela seulement si vous êtes vraiment sûr que la table est correctement décrite deux fois, comme avec la table de réflexion.J'ai eu cette erreur à l'aide de Flacon-SQLAlchemy, mais les autres solutions ne fonctionnent pas.
L'erreur ne s'est produite sur notre serveur de production, alors que tout fonctionnait bien sur mon ordinateur et sur le serveur de test.
J'ai eu un "Modèle" de classe que tous mes autres classes de base de données héritées de:
Pour une raison quelconque, l'ORM a donné des classes qui a hérité de cette classe de la même table nom de cette classe. C'est, pour chaque classe, il a essayé de faire un tableau pour qu'il appelle le tableau "modèle".
La solution a été explicitement le nom de l'enfant-tables avec le " tablename' variable de classe:
Comme mentionné dans le commentaire, je préfère le modèle étendu où le
Friendship
est une entité en soi et les liens entre les amis sont encore des entités distinctes. De cette façon, on peut stocker les propriétés qui sont symmetrial ainsi que assymetrical (ce qu'une personne pense de l'autre). En tant que tel le modèle ci-dessous devrait vous montrer ce que je veux dire:De cette façon, ajoutant une amitié est assez facile.
Donc, est mise à jour tous les attributs. Vous pouvez créer d'autres méthodes d'assistance, comme
add_friend
.Avec le
cascade
configuration ci-dessus, aussi la suppression de unUser or Friendship or UserFriend
sera assurez-vous que les deux côtés sont supprimés.Sélection tous les amis est aussi compliqué que vous le souhaitez:
print user.friends
Le vrai problème de cette solution est de s'assurer qu'il y a exactement 2
UserFriend
liens pour chaqueFriendship
. Encore une fois, lors de la manipulation des objets à partir du code, il ne devrait pas être un problème, mais la base de données sont susceptibles d'être incohérent si les importations de quelqu'un/manipule certaines données directement dans le générateur de côté.