Configuration d'une clé étrangère à une classe de base abstraite avec Django

J'ai factorisé les attributs communs de deux classes dans une classe de base abstraite, mais j'ai un autre modèle qui doit référencer l'une de ces classes. Il n'est pas possible de référencer un ABC car il n'a pas réellement de table de base de données.

L'exemple suivant devrait illustrer mon problème:

class Answer(models.Model):
    ovramt = models.ForeignKey("Ovramt")
    question = models.ForeignKey("Question")
    answer = models.CharField(max_length=3, choices=(("yes","yes"),("no","no") ("NA","N/A"))
    likelihood = models.IntegerField(choices=LIKELY_CHOICES)
    consequence = models.IntegerField(choices=CONSEQUENCE_CHOICES)

    class Meta:
        abstract = True

class Answer_A(Answer):
    resident = models.ForeignKey("Resident")
    def __unicode__(self):
        return u"%s - %s - %s" %(self.ovramt.ssa.name, self.resident, self.question)    

class Answer_B(Answer):
    def __unicode__(self):
        return u"%s - %s" %(self.ovramt.ssa.name, self.question)    

class Answer_Risk(models.Model):
    answer = models.ForeignKey("Answer")
    risk = models.CharField(max_length=200)

    def __unicode__(self):
        return self.risk

Answer_A et Answer_B sont légèrement différents en ce sens que Answer_A a également besoin d'une relation FK avec une autre table. Answer_B peut également nécessiter des attributs spécifiques tard. Le problème existerait toujours si J'avais Answer_B être la superclasse - et avoir une sous-classe Answer_A ou la composer.

Un' risque 'est le même que ce soit Answer_A ou Answer_B. j'ai aussi d'autres modèles qui doivent référencer une 'réponse' quel que soit son sous-type. Comment cela peut-il être fait? Comment Pouvez-vous référencer un type indépendamment de son sous-type?

Mise à jour:
J'essayais d'éviter une opération de jointure mais je ne pense pas pouvoir le faire. Serait-il la peine d'avoir la référence pour "résident" dans toutes les " réponses et juste l'annuler si nécessaire? Ou est-ce considéré comme une très mauvaise pratique?

30
demandé sur dalle 2008-12-15 07:16:33

2 réponses

Une relation Générique semble être la solution. Mais cela compliquera encore plus les choses.

Il me semble; votre structure de modèle est déjà plus complexe que nécessaire. Je voudrais simplement fusionner les trois modèles Answer en un seul. De cette façon:

  • Answer_Risk fonctionnerait sans modification.
  • Vous pouvez définir resident à None (NULL) dans le cas d'un Answer_A.
  • Vous pouvez renvoyer différentes représentations de chaînes en fonction de resident == None. (en d'autres mots, même la fonctionnalité)

Encore Une chose; sont vos réponses susceptibles d'avoir plus d'un risque? S'ils n'ont aucun ou un risque, vous devriez envisager de suivre d'autres implémentations:

  • utilisation d'une relation un-à-un
  • rétrograder le risque en tant que champ (ou n'importe quel nombre de champs) dans la classe Answer.

Ma principale préoccupation n'est ni la structure de la base de données ni les performances (bien que ces changements devraient améliorer les performances) mais le code la maintenabilité.

18
répondu muhuk 2012-01-06 06:15:12

Mon instinct serait de suggérer de supprimer le modificateur Abstrait sur la classe de base. Vous obtiendrez la même structure de modèle, mais la réponse sera sa propre table. L'inconvénient de ceci est que si ce sont de grandes tables et / ou vos requêtes sont complexes, les requêtes contre elles pourraient être sensiblement plus lentes.

Alternativement, vous pouvez garder vos modèles tels quels, mais remplacer la ForeignKey à Animal par une GenericForeignKey . Ce que vous perdez dans le sucre syntaxique de l'héritage du modèle, vous gagnez un peu en vitesse de requête.

Je ne crois pas qu'il soit possible de référencer un modèle de base abstrait par ForeignKey (ou quoi que ce soit fonctionnellement le même).

8
répondu Daniel Naab 2012-03-13 05:50:55