106 votes

modèles abstraits django versus héritage régulier

Outre la syntaxe, quelle est la différence entre l'utilisation d'un modèle abstrait django et l'utilisation de l'héritage Python avec les modèles django ? Avantages et inconvénients ?

MISE À JOUR : Je pense que ma question a été mal comprise et j'ai reçu des réponses concernant la différence entre un modèle abstrait et une classe qui hérite de django.db.models.Model. En fait, je veux connaître la différence entre une classe modèle qui hérite d'une classe abstraite de Django (Meta : abstract = True) et une classe Python ordinaire qui hérite de, disons, 'object' (et non de models.Model).

Voici un exemple :

class User(object):
   first_name = models.CharField(..

   def get_username(self):
       return self.username

class User(models.Model):
   first_name = models.CharField(...

   def get_username(self):
       return self.username

   class Meta:
       abstract = True

class Employee(User):
   title = models.CharField(...

178voto

Aya Points 13144

Je veux en fait connaître la différence entre une classe de modèle qui qui hérite d'une classe abstraite de Django (Meta : abstract = True) et une classe de classe Python ordinaire qui hérite de, disons, 'object' (et non de models.Model).

Django ne générera des tableaux que pour les sous-classes de models.Model donc le premier...

class User(models.Model):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

   class Meta:
       abstract = True

class Employee(User):
   title = models.CharField(max_length=255)

...entraînera la création d'un seul tableau, du type...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(255) NOT NULL,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

...alors que la seconde...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User):
   title = models.CharField(max_length=255)

...n'entraînera pas la création de tableaux.

Vous pourriez utiliser l'héritage multiple pour faire quelque chose comme ça...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User, models.Model):
   title = models.CharField(max_length=255)

...ce qui créerait une table, mais ignorerait les champs définis dans le fichier User donc vous vous retrouverez avec un tableau comme celui-ci...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

43voto

mipadi Points 135410

Un modèle abstrait crée une table avec l'ensemble des colonnes pour chaque sous-enfant, alors que l'utilisation de l'héritage Python "ordinaire" crée un ensemble de tables liées (alias "héritage multi-table"). Considérons le cas où vous avez deux modèles :

class Vehicle(models.Model):
  num_wheels = models.PositiveIntegerField()

class Car(Vehicle):
  make = models.CharField(…)
  year = models.PositiveIntegerField()

Si Vehicle est un modèle abstrait, vous aurez une seule table :

app_car:
| id | num_wheels | make | year

Cependant, si vous utilisez l'héritage Python, vous aurez deux tables :

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

vehicle_id est un lien vers une ligne dans app_vehicle qui aurait également le nombre de roues de la voiture.

Maintenant, Django va mettre tout cela sous forme d'objet pour que vous puissiez accéder à num_wheels comme un attribut sur Car mais la représentation sous-jacente dans la base de données sera différente.


Mise à jour

Pour répondre à votre dernière question, la différence entre hériter d'une classe abstraite de Django et hériter de la classe abstraite de Python est la suivante object c'est que le premier est traité comme un objet de base de données (ses tables sont donc synchronisées avec la base de données) et qu'il a le comportement d'un objet Model . Hériter d'un Python ordinaire object ne donne à la classe (et à ses sous-classes) aucune de ces qualités.

25voto

Bernhard Vallant Points 18035

La principale différence réside dans la manière dont sont créées les tables des bases de données pour les modèles. Si vous utilisez l'héritage sans abstract = True Django crée une table distincte pour le modèle parent et le modèle enfant, qui contient les champs définis dans chaque modèle.

Si vous utilisez abstract = True pour la classe de base, Django ne créera une table que pour les classes qui héritent de la classe de base - peu importe que les champs soient définis dans la classe de base ou dans la classe héritante.

Les avantages et les inconvénients dépendent de l'architecture de votre application. Étant donné les exemples de modèles suivants :

class Publishable(models.Model):
    title = models.CharField(...)
    date = models.DateField(....)

    class Meta:
        # abstract = True

class BlogEntry(Publishable):
    text = models.TextField()

class Image(Publishable):
    image = models.ImageField(...)

Si le Publishable n'est pas abstraite, Django créera une table pour les publiables avec les colonnes title y date et des tableaux séparés pour BlogEntry y Image . L'avantage de cette solution est que vous êtes en mesure d'effectuer des requêtes sur l'ensemble du territoire. tous publiables pour les champs définis dans le modèle de base, qu'il s'agisse d'articles de blog ou d'images. Mais Django devra donc faire des jointures si vous faites par exemple des requêtes pour les images... Si l'on fait Publishable abstract = True Django ne créera pas de table pour Publishable mais uniquement pour les entrées de blog et les images, contenant tous les champs (y compris les champs hérités). Cela serait pratique car aucune jointure ne serait nécessaire pour une opération telle que get.

Voir aussi Documentation de Django sur l'héritage de modèle .

10voto

Adrián Points 3217

Je voulais juste ajouter quelque chose que je n'ai pas vu dans les autres réponses.

Contrairement aux classes python, le masquage du nom du champ n'est pas autorisé avec l'héritage des modèles.

Par exemple, j'ai expérimenté des problèmes avec un cas d'utilisation comme le suivant :

J'avais un modèle héritant de l'auth de Django. PermissionMixin :

class PermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django's Group and Permission model using the ModelBackend.
    """
    is_superuser = models.BooleanField(_('superuser status'), default=False,
        help_text=_('Designates that this user has all permissions without '
                    'explicitly assigning them.'))
    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
        blank=True, help_text=_('The groups this user belongs to. A user will '
                                'get all permissions granted to each of '
                                'his/her group.'))
    user_permissions = models.ManyToManyField(Permission,
        verbose_name=_('user permissions'), blank=True,
        help_text='Specific permissions for this user.')

    class Meta:
        abstract = True

    # ...

Ensuite, j'avais mon mixin qui, entre autres choses, devait remplacer la fonction related_name de la groups champ. C'était donc plus ou moins comme ça :

class WithManagedGroupMixin(object):
    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
        related_name="%(app_label)s_%(class)s",
        blank=True, help_text=_('The groups this user belongs to. A user will '
                            'get all permissions granted to each of '
                            'his/her group.'))

J'utilisais ces 2 mixins comme suit :

class Member(PermissionMixin, WithManagedGroupMixin):
    pass

Alors oui, je m'attendais à ce que ça marche mais ça n'a pas marché. Mais le problème était plus grave car l'erreur que je recevais ne pointait pas du tout vers les modèles, je n'avais aucune idée de ce qui n'allait pas.

En essayant de résoudre ce problème, j'ai décidé par hasard de modifier mon mixin et de le convertir en un mixin de modèle abstrait. L'erreur s'est transformée en ceci :

django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'

Comme vous pouvez le constater, cette erreur explique ce qui se passe.

C'était une énorme différence, à mon avis :)

2voto

Brent Washburne Points 2453

La principale différence réside dans le fait que vous héritez de la classe User. Une version se comportera comme une simple classe, et l'autre se comportera comme un modele Django.

Si vous héritez de la version "objet" de base, votre classe Employé sera juste une classe standard, et first_name ne fera pas partie d'une table de base de données. Vous ne pouvez pas créer de formulaire ou utiliser d'autres fonctionnalités de Django avec elle.

Si vous héritez de la version models.Model, votre classe Employee disposera de toutes les méthodes d'une classe Django Modèle et il héritera du champ first_name en tant que champ de base de données pouvant être utilisé dans un formulaire.

Selon la documentation, un Modèle abstrait "fournit un moyen de factoriser les informations communes au niveau Python, tout en ne créant qu'une seule table de base de données par modèle enfant au niveau de la base de données."

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