Modèles Django et classes abstraites


Bonjour Sam & Max,

Je suis le génie de la l’ANPE. Enigma, tu m’as trouvé, et tu as le droit à 3 voeux.

J’ai bien aimé votre blog consacré a dynamiser la communauté francophone python et je voudrais vous poser une petite question.
En fait, Quand il s’agit d’écrire un modèle, ce dernier doit hériter de la classe models.Model

par exemple:
class Entry(models.Model):

je me demande pourquoi exactement models.Model ?
et pourquoi ne pas faire l’héritage directement comme ça:
class Entry(Model)


Une explication de la syntaxe d’héritage des modèles Django ? Qu’il en soit ainsi.

On peut faire les deux. C’est une question d’import.

Si tu fais:

from django import models

Tu importes le module models.

Alors si tu veux hériter de la classe Model du module models, tu dois préfixer la classe du module (c’est ce qu’on appelle un namespace) : class Entry(models.Model).

Si par contre tu fais :

from django.models import Model

Tu importes la classe Model. Tu peux donc l’utiliser directement : class Entry(Model)

Le choix entre l’un et l’autre est essentiellement une question de style. En Django, pour les modèles on utilise from django import models car on va généralement également utiliser beaucoup de champs (models.IntegerField, models.BooleanField, etc) et que ça évite de tous les importer.

Aussi, je voudrais savoir qu’est ce qu’une Abstract base class ? ( car je sais que c’est un peu ça mais j’arrive pas à faire le lien )


Je ne peux pas faire tomber amoureux, ressusciter les morts ni faire des classes abstraites en Python. Mais je peux t’expliquer pourquoi. Accordé !

Une Abstract Base Class n’existe pas vraiment en Python. Il y a bien un module abc pour les simuler en utilisant des metaclasses, mais il est peu probable que tu en aies jamais besoin.

Dans d’autres langages, les classes abstraites sont des classes “à trou”. C’est à dire qu’elles ne sont pas complètes. On en hérite pour récupérer une partie de leur comportement, et on écrit le reste.

Imagine une classe Vehicule, qui sert de classe de base à une classe Voiture et une classe Moto :

class Vehicule(object):
 
 
    def __init__(carburant):
 
        self.carburant = carburant

Ceci est une classe abstraite. Elle possède des éléments communs à tous les véhicules, mais ne sait pas rouler. Chaque enfant doit implémenter la méthode rouler() :

class Moto(Vehicule):
 
    def rouler(km):
 
        self.carburant -= km * 3
        print 'Brrrrrrrrrrrrrrrrrr'
 
 
class Voiture(Vehicule):
 
    def rouler(km):
 
        self.carburant -= km * 7
        print 'Vrouuuuuuum'

Une classe abstraite est donc une classe incomplète, utile pour rassembler du code commun aux autres classes, mais qui ne marche pas d’elle même.

Dans d’autres langages, ce concept est formalisé par des mots clés, et des vérifications. Pas en Python : toutes les classes sont égales.

Maintenant le concept des classes abstraites dans Django est une application particulière. Je pense que tu poses la question parce que tu as vu ça :

class Vehicule(models.Model):
 
    class Meta:
 
        abstract = True

Dans ce cas particulier, le principe est le même que plus haut, mais appliqué aux models.

L’ORM de django crée en base de donnée une table par classe qui hérite de models.Model. Ce n’est pas ce que tu veux pour Vehicule : Vehicule ne marche pas par elle même, aucun intérêt de créer une table pour elle.

Ainsi Django le formalise l’aspect “abstrait” avec un attribut. Si l’attribut abstract est sur True, Django ne créera pas de table en base de donnée pour ce modèle, car il sait que c’est une classe abstraite, et qui donc n’est pas destinée à être utilisée directement. Tous les attributs du modèle Vehicule qui correspondent à des champs seront copiés dans les enfants, et seront des champs de leurs tables respectives.

Je vous remercie d’avance, et j’aimerais bien si c’est possible que la réponse soit comme le prochain sujet comme ça tout le monde en profite.


Tes désirs sont des ordres, maître.

(Comme d’hab, personne ne fait le vœu de libérer le génie, hein, bande de connards !)

16 thoughts on “Modèles Django et classes abstraites

  • gardouille

    Django et le “D” n’est pas prononcé! Contrairement à cette version française ou c’est complètement l’inverse.

    QUOI? Me suis trompé de sujet?
    Sous prétexte que je bouffe pas de python, j’ai pas le droit de commenter? :þ

  • kontre

    Un moyen de faire une classe abstraite à la main est de lever l’exception NotImplementedError dans les fonctions virtuelles. C’est pas super utile point de vue fonctionnement, mais ça peut permettre de montrer visuellement quelles fonctions sont à définir dans les classes enfant :

    class ClasseVirtuelle(object):
        methode_virtuelle(self):
            u"""Méthode virtuelle à réimplémenter dans les classes enfant.
            """
            raise NotImplementedError

    C’est d’ailleurs dans la doc : http://docs.python.org/2/library/exceptions.html?highlight=notimplemented#exceptions.NotImplementedError

  • Etienne

    Si tu étais un génie, mon premier voeu serait de voir se réaliser autant de voeux que je veux. Avec le deuxième je créerais un nouveau génie tout neuf. Et avec le troisième je te libérerais.

    Tu ne recules décidément devant aucune audace stylistique, Sam.

  • enigma

    Merci Sam.

    Je pense que j’ai abordé un bon sujet et je voudrai ajouter quelque chose:

    1-2) Pour mes 2 premieres questions: le namespacing pourrait être utile à résoudre les conflits, par exmaple:

    si on importe tout le contenu du module time comme ça:
    from time import *

    et on declare une variable sleep à None :
    sleep = None

    si on fait appel à la variable sleep du module time cela cause une erreur.
    >>> sleep(3)
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: 'NoneType' object is not callable
    >>>

    Donc pour travailler proprement, il faut refaire le code comme ça:

    import time

    sleep = None
    time.sleep()

    3) pour votre 3eme reponse: tout est clair et j’ajoute rien

  • Sam Post author

    < gonzesse >Un génie tout neuf. Genre je suis un génie d’occaz c’est ça ? Bande de nazes !< / gonzesse >

  • Etienne

    Mais non, mais non mon petit Samounet, y’a pas meilleur génie que toi. D’ailleurs, le nouveau, ce sera toi son chef. Et tu pourras même le former si tu veux! Aaaah, tu vois…

  • enigma

    Non un génie fraîchement sorti de la lampe, et qui a des problèmes avec l’ANPE peut être. :)

  • Etienne

    zut, j’avais taggé “diplomate” et “fin diplomate” mais il veut décidément pas prendre ce qui évoque un tag html de près ou de loin.

  • Sam Post author

    Parceque des milliers de codeurs meilleurs que nous s’en passent tous les jours. C’est généralement un bon indicateur probabilistique. Pas infaillible, mais assez probant;

  • Etienne

    @kontre
    justement, j’ai rajouté un espace après le ”, rien à faire

  • Etienne

    Là il vient de me sucrer carrément:
    “avant le {plus petit} et”, ainsi que le “{plus grand}” qui devait être entre les deux apostrophes

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.