10 votes

Modèles abstraits et clés étrangères en Django

Je travaille sur un projet django dans lequel je crée un ensemble de trois modèles abstraits que j'utiliserai pour une variété d'applications plus tard. Le problème auquel je suis confronté est que je veux connecter ces modèles via une clé étrangère mais django me dit qu'il ne peut pas attribuer de clés étrangères à un modèle abstrait.

Ma solution actuelle est d'attribuer des clés étrangères lorsque j'instancie la classe dans mes autres applications. Cependant, j'écris actuellement un gestionnaire pour les classes abstraites (livre et pages) et j'aurais besoin d'accéder à ces clés étrangères. Ce que j'essaie essentiellement de faire, c'est d'obtenir le nombre de mots qu'un livre contient de manière statique, donc sans le stocker dans un champ de la page ou du livre.

Le modèle ressemble à ceci :

class Book(models.Models):
    name = models.CharField(...)
    author = models.CharField(...)
    ...

    class Meta:
        abstract = True

class Page(models.Models):
    book = models.ForeignKey(Book)
    chapter = models.CharField(...)
    ...

    class Meta:
        abstract = True

class Word(models.Models):
    page = models.ForeignKey(Page)
    line = models.IntegerField(...)
    ...

    class Meta:
        abstract = True

Remarquez que ce modèle ici est juste pour donner un exemple de ce que j'essaie de faire, donc savoir si ce modèle (Livre-Page-Mot) a du sens d'un point de vue implémentation n'est pas nécessaire.

13voto

Michael C. O'Connor Points 4462

Peut-être que ce dont vous avez besoin ici est un GenericForeignKey, puisque vous ne savez pas réellement à quel modèle vos ForeignKey vont pointer? Cela signifie que vous perdrez certaines des garanties de "type-safety" d'une relation normale, mais cela vous permettra de spécifier ces relations de manière plus générale. Voir https://docs.djangoproject.com/fr/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericForeignKey

L'héritage de modèles Django est une bonne chose, et pratique pour rendre vos modèles DRYer, mais ne fonctionne pas toujours bien avec les idées polymorphes que nous avons généralement des classes.

5voto

rrauenza Points 186

Que diriez-vous de cette approche? Je envisage de l'utiliser moi-même pour retarder la définition de la relation jusqu'à ce que j'hérite.

# Ceci est un exemple très artificiel (mais simple).

def AbstractBook(AuthorModel):                                                  
    class AbstractBookClass(Model):                                             
        name = CharField(max_length=10)                                         
        author = ForeignKey(AuthorModel)                                        
        class Meta:                                                             
            abstract = True                                                     
    return AbstractBookClass                                                    

class AbstractAuthor(Model):                                                    
    name = CharField(max_length=10)                                             
    class Meta:                                                                 
        abstract = True                                                         

class BadAuthor(AbstractAuthor):                                                
    pass                                                                        

class BadBook(AbstractBook(BadAuthor)):                                         
    pass                                                                        

class GoodAuthor(AbstractAuthor):                                               
    pass                                                                        

class GoodBook(AbstractBook(GoodAuthor)):                                       
    pass

0voto

Tiphareth Points 178

Deux choses :

1) La façon dont vous avez construit votre schéma, vous aurez besoin d'un GenericForeignKey, comme déjà mentionné. Mais vous devez prendre en compte que Book through Page a une relation many-to-many avec Word, tandis qu'un GenericForeignKey ne réalise qu'une relation one-to-many. Django n'a rien de prêt à l'emploi pour le schéma normalisé. Ce que vous devrez faire (si vous vous souciez de la normalisation) est de mettre en œuvre l'intermédiaire (avec "through" pour les Modèles concrets) vous-même.

2) Si vous vous préoccupez du traitement du langage, l'utilisation d'une base de données relationnelle (avec ou sans ORM de Django) n'est pas une approche très efficace, compte tenu de la taille de la base de données résultante et du temps de requête après quelques dizaines de livres. Ajoutez à cela les colonnes supplémentaires dont vous aurez besoin pour rechercher vos jointures en raison des Modèles abstraits, et cela deviendra bientôt très impraticable. Je pense qu'il serait plus bénéfique d'examiner d'autres approches, par exemple en ne stockant que les agrégats et/ou en dénormalisant (voire en examinant des systèmes de stockage non relationnels dans ce cas), en fonction de vos requêtes et de vos vues.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X