web-dev-qa-db-fra.com

Django modèle avec 2 clés étrangères de la même table

Je voulais un modèle Django avec 2 clés étrangères de la même table. C'est une table d'événements qui a 2 colonnes pour les employés: "l'acteur" et le "récepteur". Mais je reçois cette erreur:

Erreur: un ou plusieurs modèles n'ont pas validé: tasks.task: le modèle intermédiaire TaskEvent a plus d'une clé étrangère vers Employee, ce qui est ambigu et n'est pas autorisé.

Y a-t-il une meilleure façon de modéliser cela? Merci

Je pense que je vais ajouter un TaskEvent_to_Employee table. Il y aura deux enregistrements, un pour chacun des deux employés liés à chaque TaskEvent. Quelqu'un connaît une solution de contournement plus facile?

42
Josh

Je ne l'ai pas encore fait, mais j'ai utilisé inspectdb pour générer le fichier models.py à partir d'une base de données existante qui fait exactement cela - c'est ce que inspectdb a rejeté, donc cela devrait fonctionner:

creator = models.ForeignKey(Users, null=True, related_name='creator')
assignee = models.ForeignKey(Users, null=True, related_name='assignee')

J'espère que cela fonctionne pour vous - si ce n'est pas le cas, je vais aussi avoir un problème.

84
Technical Bard

Je pense que ce que vous recherchez est la propriété related_name sur ForeignKeyFields. Cela vous permettra de référencer la même table, mais donnez Django des noms spéciaux pour la relation.

Plus d'informations:

7
Justin Abrahms

D'après le message d'erreur, il semble que vous essayez de placer deux clés étrangères sur le même objet sur une table intermédiaire utilisée via l'argument through vers ManyToManyField, la documentation pour qui indique :

Lorsque vous configurez le modèle intermédiaire, vous spécifiez explicitement les clés étrangères des modèles impliqués dans la relation ManyToMany. Cette déclaration explicite définit la relation entre les deux modèles.

Il existe quelques restrictions sur le modèle intermédiaire:

  • Votre modèle intermédiaire doit contenir une - et une seule - clé étrangère vers le modèle cible (ce serait Personne dans notre exemple). Si vous avez plusieurs clés étrangères, une erreur de validation sera déclenchée.
  • Votre modèle intermédiaire doit contenir une - et une seule - clé étrangère vers le modèle source (ce serait Group dans notre exemple). Si vous avez plusieurs clés étrangères, une erreur de validation sera déclenchée.
7
Jonny Buchanan

Utiliser related_name était ma solution:

class Sample(models.model):
    ...

class Mymodel(models.model):
    example1 = models.ForeignKey(Sample, related_name='sample1')
    example2 = models.ForeignKey(Sample, related_name='sample2')
1
Alex Jolig

Le fait que deux colonnes font partie d'une même table implique que les deux champs sont liés, donc les référencer individuellement n'est pas idéal. La clé étrangère de votre modèle doit être la clé primaire de la table à laquelle vous faites référence:

event = models.ForeignKey('event')

Vous feriez alors référence aux colonnes comme telles:

foo.event.actor
foo.event.receiver

Si vous le souhaitez, vous pouvez également modifier la façon dont votre classe/modèle référence les attributs étrangers avec des propriétés. Dans votre classe, vous feriez ce qui suit:

@property
def actor(self):
  return self.event.actor
@property
def receiver(self):
  return self.event.receiver

Cela vous permettrait d'appeler ensuite foo.actor et foo.receiver mais je crois que plus long, foo.event.actor serait plus Pythonic

0
awithrow