# Documentation Django 6.0.7

# Modèles

Un modèle est la source d’information unique et définitive à propos de vos données. Il contient les champs et le comportement essentiels des données que vous stockez. Généralement, chaque modèle correspond à une seule table de base de données.

Les bases :

- Chaque modèle est une classe Python qui hérite de `django.db.models.Model`.

- Chaque attribut du modèle représente un champ de base de données.

- Avec tout ça, Django vous offre une API d’accès à la base de données générée automatiquement ; voir Création de requêtes.

## Exemple rapide

Cet exemple de modèle définit une personne (`Person`) avec un prénom (`first_name`) et un nom (`last_name`) :

    from django.db import models

    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)

`first_name` et `last_name` sont des champs du modèle. Chaque champ est défini comme un attribut de classe, et chaque attribut correspond à une colonne de base de données.

Le modèle `Person` ci-dessus va créer une table de base de données comme celle-ci :

    CREATE TABLE myapp_person (
        "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
        "first_name" varchar(30) NOT NULL,
        "last_name" varchar(30) NOT NULL
    );

Quelques notes techniques :

- Le nom de la table, `myapp_person`, est automatiquement dérivé de certaines métadonnées du modèle mais peut être surchargé. Consultez Noms de tables pour plus de détails.

- Un champ `id` est ajouté automatiquement, mais ce comportement peut être adapté. Voir Champs clé primaire automatiques.

- Le code SQL `CREATE TABLE` de cet exemple est mis en forme avec la syntaxe PostgreSQL, mais il est utile de relever que Django utilise du code SQL adapté au moteur de base de données indiqué dans votre fichier de réglages.

## Utilisation des modèles

Après avoir défini les modèles, il faut indiquer à Django que vous souhaitez utiliser ces modèles. Vous pouvez le faire en éditant votre fichier de réglages et en modifiant le réglage `INSTALLED_APPS` pour y ajouter le nom du module qui contient `models.py`.

Par exemple, si le modèle de votre application se trouve dans le module `myapp.models` (la structure de paquet créée pour une application par le script `manage.py startapp`), `INSTALLED_APPS` devrait contenir :

    INSTALLED_APPS = [
        # ...
        "myapp",
        # ...
    ]

Lorsque vous ajoutez de nouvelles applications à `INSTALLED_APPS`, n’oubliez pas ensuite de lancer `manage.py migrate`, en créant éventuellement d’abord des migrations pour ces applications avec `manage.py makemigrations`.

## Champs

La partie la plus importante d’un modèle (et la seule qui soit obligatoire) est la liste des champs de base de données qu’il définit. Les champs sont définis par des attributs de classe. Faites attention à ne pas choisir des noms de champs qui entrent en conflit avec l’API des modèles comme `clean`, `save` ou `delete`.

Exemple :

    from django.db import models

    class Musician(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        instrument = models.CharField(max_length=100)

    class Album(models.Model):
        artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
        name = models.CharField(max_length=100)
        release_date = models.DateField()
        num_stars = models.IntegerField()

### Types de champs

Chaque champ de votre modèle doit être une instance de la classe `Field` appropriée. Django utilise les types des classes de champs pour déterminer un certain nombre de choses :

- Le type de la colonne, qui indique à la base de données le genre de données à stocker (par ex. `INTEGER`, `VARCHAR`, `TEXT`).

- Le composant HTML par défaut à utiliser lors de la création d’un champ de formulaire (par ex. : `<input type="text">`, `<select>`).

- Les exigences minimales de validation, utilisées dans l’administration de Django et dans les formulaires générés automatiquement.

Django est fourni avec des dizaines de types de champs intégrés ; vous trouverez la liste complète dans la référence des champs de modèle. Vous pouvez facilement écrire vos propres champs si ceux proposés par Django ne font pas l’affaire ; voir Écriture de champs de modèles personnalisés.

### Options des champs

Chaque champ accepte un certain nombre de paramètres spécifiques (documentés dans la référence des champs de modèle). Par exemple, `CharField` (et ses sous-classes) exige un paramètre `max_length` indiquant la taille du champ de base de données `VARCHAR` qui stockera les données.

Il existe aussi un ensemble de paramètres communs à tous les types de champs. Ils sont tous facultatifs. Ils sont décrits en détails dans la référence, mais voici un résumé rapide de ceux qui sont le plus souvent utilisés :

`null`

  Si la valeur est `True`, Django stocke les valeurs vides avec `NULL` dans la base de données. La valeur par défaut est `False`.

`blank`

  Si la valeur est `True`, le champ peut être vide. La valeur par défaut est `False`.

  Notez que ce n’est pas la même chose que `null`. `null` est purement lié à la base de données alors que `blank` est lié à la validation. Si un champ possède `blank=True`, la validation de formulaire permet la saisie d’une valeur vide. Si un champ possède `blank=False`, le champ est obligatoire.

`choices`

  Une séquence de tuples binaires, un dictionnaire, un type énumération ou un exécutable (n’attendant aucun argument et renvoyant l’un des formats mentionnés) pour constituer les choix de ce champ. Quand ce paramètre est présent, le composant de formulaire par défaut est une liste déroulante au lieu du champ de texte standard et seules les valeurs proposées dans les choix indiqués seront acceptées.

  Une liste de choix ressemble à ceci :

      YEAR_IN_SCHOOL_CHOICES = [
          ("FR", "Freshman"),
          ("SO", "Sophomore"),
          ("JR", "Junior"),
          ("SR", "Senior"),
          ("GR", "Graduate"),
      ]

  Note

  Une nouvelle migration est produite chaque fois que l’ordre des choix `choices` change.

  Le premier élément de chaque tuple est la valeur qui sera stockée en base de données. Le second élément est affiché par le composant du champ de formulaire.

  Étant donné une instance de modèle, on peut accéder à la valeur d’affichage d’un champ à choix en utilisant la méthode `get_FOO_display()`. Par exemple

      from django.db import models

      class Person(models.Model):
          SHIRT_SIZES = {
              "S": "Small",
              "M": "Medium",
              "L": "Large",
          }
          name = models.CharField(max_length=60)
          shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

      >>> p = Person(name="Fred Flintstone", shirt_size="L")
      >>> p.save()
      >>> p.shirt_size
      'L'
      >>> p.get_shirt_size_display()
      'Large'

  Vous pouvez aussi utiliser des classes d’énumération pour définir `choices` d’une manière concise

      from django.db import models

      class Runner(models.Model):
          MedalType = models.TextChoices("MedalType", "GOLD SILVER BRONZE")
          name = models.CharField(max_length=60)
          medal = models.CharField(blank=True, choices=MedalType, max_length=10)

  D’autres exemples sont disponibles dans la référence des champs de modèles.

`default`

  La valeur par défaut du champ. Cela peut être une valeur ou un objet exécutable. Dans ce dernier cas, l’objet est appelé lors de chaque création d’un nouvel objet.

`db_default`

  La valeur par défaut générée en base de données pour ce champ. Il peut s’agir d’une valeur littérale ou d’une fonction de base de données.

  Si `db_default` et `Field.default` sont tous deux définis, `default` aura la priorité lors de la création d’instance à partir de code Python. `db_default` sera tout de même défini au niveau de la base de données et sera utilisé dans les cas d’insertion effectuée en dehors de l’ORM Django ou lors d’ajout de nouveaux champs dans une migration.

`help_text`

  Texte d’aide supplémentaire à afficher avec le composant de formulaire. Utile pour la documentation même si le champ n’est pas utilisé dans un formulaire.

`primary_key`

  Si la valeur est `True`, ce champ représentera la clé primaire du modèle.

  Si vous n’indiquez aucun paramètre `primary_key=True` dans les champs d’un modèle, Django ajoute automatiquement un champ pour constituer une clé primaire ; il n’est donc pas nécessaire de définir le paramètre `primary_key=True` pour un champ sauf si vous souhaitez modifier le comportement par défaut de clé primaire automatique. Pour en savoir plus, consultez Champs clé primaire automatiques.

  Le champ de clé primaire est en lecture seule. Si vous modifiez la valeur de la clé primaire d’un objet existant et que vous l’enregistrez, un nouvel objet est créé en parallèle à l’ancien. Par exemple :

      from django.db import models

      class Fruit(models.Model):
          name = models.CharField(max_length=100, primary_key=True)

      >>> fruit = Fruit.objects.create(name="Apple")
      >>> fruit.name = "Pear"
      >>> fruit.save()
      >>> Fruit.objects.values_list("name", flat=True)
      <QuerySet ['Apple', 'Pear']>

`unique`

  Si la valeur est `True`, ce champ doit être unique dans toute la table.

Répétons encore une fois que ce n’était que de courtes descriptions des options de champs les plus courantes. Des détails complets peuvent être obtenus dans la référence des options communes des champs de modèle.

### Champs clé primaire automatiques

Par défaut, Django donne à chaque modèle une clé primaire autoincrémentée dont le type est défini par application selon `AppConfig.default_auto_field` ou globalement dans le réglage `DEFAULT_AUTO_FIELD`. Par exemple

    id = models.BigAutoField(primary_key=True)

Si vous souhaitez spécifier une clé primaire personnalisée, ajoutez `primary_key=True` à l’un de vos champs. Si Django voit que vous avez explicitement défini `Field.primary_key`, il n’ajoutera pas de colonne `id` automatique.

Pour chaque modèle, il est obligatoire d’avoir un et un seul champ ayant le paramètre `primary_key=True` (qu’il soit déclaré explicitement ou ajouté automatiquement).

### Noms de champs verbeux

Chaque type de champ, à l’exception de `ForeignKey`, `ManyToManyField` et `OneToOneField`, accepte un premier paramètre positionnel facultatif, un nom verbeux. Si le nom verbeux n’est pas défini, Django le crée automatiquement en se basant sur le nom d’attribut du champ, remplaçant les soulignements par des espaces.

Dans cet exemple, le nom verbeux est `"person's first name"`:

    first_name = models.CharField("person's first name", max_length=30)

Dans cet exemple, le nom verbeux est `"first name"`:

    first_name = models.CharField(max_length=30)

`ForeignKey`, `ManyToManyField` et `OneToOneField` exigent que le premier paramètre soit une classe de modèle, il est donc nécessaire d’utiliser le paramètre nommé `verbose_name`:

    poll = models.ForeignKey(
        Poll,
        on_delete=models.CASCADE,
        verbose_name="the related poll",
    )
    sites = models.ManyToManyField(Site, verbose_name="list of sites")
    place = models.OneToOneField(
        Place,
        on_delete=models.CASCADE,
        verbose_name="related place",
    )

La convention est de ne pas mettre en majuscule la première lettre de `verbose_name`. Django le fera automatiquement là où il pense que c’est nécessaire.

### Relations

Clairement, la puissance des base de données relationnelles se trouve dans les liaisons entre tables. Django propose des méthodes pour définir les trois types de relations les plus courantes : plusieurs-à-un, plusieurs-à-plusieurs et un-à-un.

#### Relations plusieurs-à-un

Pour définir une relation plusieurs-à-un, utilisez `django.db.models.ForeignKey`. Son utilisation est pareille à celle des autres types de champs `Field` : il s’agit d’un attribut de classe d’un modèle.

`ForeignKey` exige un paramètre positionnel : la classe à laquelle le modèle est lié.

Par exemple, si un modèle `Car` (voiture) possède un `Manufacturer` (fabriquant), c’est-à-dire qu’un `Manufacturer` peut produire plusieurs voitures mais chaque `Car` n’a qu’un seul `Manufacturer`, voici le code correspondant :

    from django.db import models

    class Manufacturer(models.Model):
        # ...
        pass

    class Car(models.Model):
        manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
        # ...

Il est aussi possible de créer des relations récursives (un objet avec une relation plusieurs-à-un avec lui-même) et des relations vers des modèles non encore définis ; consultez la référence des champs de modèle pour plus de détails.

Il est recommandé mais non obligatoire que le nom d’un champ `ForeignKey` (`manufacturer` dans l’exemple ci-dessus) soit égal au nom du modèle en minuscules. Vous pouvez nommer le champ de la manière qui vous convient. Par exemple :

    class Car(models.Model):
        company_that_makes_it = models.ForeignKey(
            Manufacturer,
            on_delete=models.CASCADE,
        )
        # ...

Voir aussi

Les champs `ForeignKey` acceptent quelques paramètres supplémentaires qui sont présentés dans la référence des champs de modèle. Ces options aident à spécifier le fonctionnement de la relation ; toutes sont facultatives.

Pour plus de détails sur l’accès aux objets par référence liée inverse, consultez l’exemple de l’accès aux relations inverses.

Pour des exemples de code, consultez les exemples de relations plusieurs-à-un entre modèles.

#### Relations plusieurs-à-plusieurs

Pour définir une relation plusieurs-à-plusieurs, utilisez `django.db.models.ManyToManyField`. Son utilisation est pareille à celle des autres types de champs `Field` : il s’agit d’un attribut de classe d’un modèle.

`ManyToManyField` exige un paramètre positionnel : la classe à laquelle le modèle est lié.

Par exemple, si une `Pizza` possède plusieurs objets `Topping` (garniture), c’est-à-dire qu’un `Topping` peut se trouver sur plusieurs pizzas et chaque `Pizza` possède plusieurs garnitures, voici comment ce cas de figure serait représenté :

    from django.db import models

    class Topping(models.Model):
        # ...
        pass

    class Pizza(models.Model):
        # ...
        toppings = models.ManyToManyField(Topping)

Comme pour `ForeignKey`, il est aussi possible de créer des relations récursives (un objet avec une relation plusieurs-à-plusieurs avec lui-même) et des relations vers des modèles non encore définis.

Il est recommandé mais non obligatoire que le nom d’un champ `ManyToManyField` (`toppings` dans l’exemple ci-dessus) soit un pluriel décrivant l’ensemble des objets modèles liés.

Que le champ `ManyToManyField` soit placé sur un modèle ou l’autre ne change pas grand chose, mais il est essentiel de ne le mettre que dans un des modèles, pas dans les deux.

Généralement, les instances `ManyToManyField` devraient être placées dans l’objet qui va être modifié par un formulaire. Dans l’exemple ci-dessus, les `toppings` sont dans `Pizza` (plutôt que ce soit `Topping` qui possède un champ `ManyToManyField` de `pizzas` ) parce qu’il est plus logique d’imaginer une pizza ayant plusieurs garnitures qu’une garniture se trouvant dans plusieurs pizzas. De la manière dont les choses ont été définies ci-dessus, le formulaire `Pizza` permettra de choisir des garnitures.

Voir aussi

Consultez les exemples de relations plusieurs-à-plusieurs entre modèles pour voir un exemple complet.

Les champs `ManyToManyField` acceptent aussi quelques paramètres supplémentaires qui sont présentés dans la référence des champs de modèle. Ces options aident à spécifier le fonctionnement de la relation ; toutes sont facultatives.

#### Champs supplémentaires dans les relations plusieurs-à-plusieurs

Lorsque vous devez gérer des relations plusieurs-à-plusieurs comme le mélange et la combinaison de pizzas et de garnitures, un `ManyToManyField` standard suffit. Cependant, il est parfois nécessaire d’associer des données à la relation entre deux modèles.

Par exemple, considérez le cas d’une application faisant le lien entre des musiciens et les groupes musicaux auxquels ils appartiennent. Une relation plusieurs-à-plusieurs existe entre une personne et les groupes dont elle est membre, il est donc possible d’utiliser un champ `ManyToManyField` pour représenter cette relation. Cependant, il y a de nombreux détails au sujet de l’appartenance au groupe qu’il peut être intéressant de conserver, comme par exemple la date à laquelle la personne à rejoint le groupe.

Pour ces situations, Django permet d’indiquer le modèle qui sera utilisé pour spécifier la relation plusieurs-à-plusieurs. Il est alors possible de définir des champs supplémentaires dans le modèle intermédiaire. Ce dernier est associé au champ `ManyToManyField` en utilisant le paramètre `through` qui va pointer vers le modèle agissant comme intermédiaire. Dans notre exemple de musique, le code pourrait ressembler à ceci :

    from django.db import models

    class Person(models.Model):
        name = models.CharField(max_length=128)

        def __str__(self):
            return self.name

    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(Person, through="Membership")

        def __str__(self):
            return self.name

    class Membership(models.Model):
        person = models.ForeignKey(Person, on_delete=models.CASCADE)
        group = models.ForeignKey(Group, on_delete=models.CASCADE)
        date_joined = models.DateField()
        invite_reason = models.CharField(max_length=64)

        class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=["person", "group"], name="unique_person_group"
                )
            ]

Lorsque vous définissez le modèle intermédiaire, vous indiquez explicitement les clés étrangères vers les modèles impliqués dans la relation plusieurs-à-plusieurs. Cette déclaration explicite définit comment les deux modèles sont reliés.

Si vous ne souhaitez pas des associations multiples entre les mêmes instances, ajoutez une contrainte `UniqueConstraint` incluant les champs de liaison (`from` et `to`). Les tables plusieurs-à-plusieurs automatiquement générées par Django contiennent une telle contrainte.

Il y a quelques restrictions concernant le modèle intermédiaire :

- Le modèle intermédiaire doit contenir une et une seule clé étrangère vers le modèle source (qui correspondrait à `Group` dans notre exemple), ou alors vous devez explicitement indiquer à Django les clés étrangères à employer pour les relations en utilisant `ManyToManyField.through_fields`. S’il y a plus d’une clé étrangère et que `through_fields` n’est pas précisé, une erreur de validation est produite. C’est exactement le même procédé pour la clé étrangère vers le modèle cible (qui correspondrait à `Person` dans notre exemple).

- Pour un modèle ayant une relation plusieurs-à-plusieurs avec lui-même au travers d’un modèle intermédiaire, deux clés étrangères vers le même modèle sont autorisées, mais elles seront considérées comme les deux (différentes) parties de la relation plusieurs-à-plusieurs. Si `through_fields` n’est pas indiqué, la première clé étrangère sera créée pour représenter le côté source du champ `ManyToManyField` alors que la seconde clé représentera le côté cible. S’il doit y avoir plus de deux clés étrangères, vous devez indiquer `through_fields` pour définir explicitement les clés étrangères à utiliser, sinon une erreur de validation sera générée.

Après avoir configuré le champ `ManyToManyField` afin qu’il utilise le modèle intermédiaire (`Membership`, dans ce cas), tout est prêt pour commencer à créer des relations plusieurs-à-plusieurs. Cela s’effectue en créant des instances du modèle intermédiaire :

    >>> ringo = Person.objects.create(name="Ringo Starr")
    >>> paul = Person.objects.create(name="Paul McCartney")
    >>> beatles = Group.objects.create(name="The Beatles")
    >>> m1 = Membership(
    ...     person=ringo,
    ...     group=beatles,
    ...     date_joined=date(1962, 8, 16),
    ...     invite_reason="Needed a new drummer.",
    ... )
    >>> m1.save()
    >>> beatles.members.all()
    <QuerySet [<Person: Ringo Starr>]>
    >>> ringo.group_set.all()
    <QuerySet [<Group: The Beatles>]>
    >>> m2 = Membership.objects.create(
    ...     person=paul,
    ...     group=beatles,
    ...     date_joined=date(1960, 8, 1),
    ...     invite_reason="Wanted to form a band.",
    ... )
    >>> beatles.members.all()
    <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>

Vous pouvez aussi utiliser `add()`, `create()` ou `set()` pour créer des relations, tant que vous indiquez `through_defaults` pour tout champ obligatoire :

    >>> beatles.members.add(john, through_defaults={"date_joined": date(1960, 8, 1)})
    >>> beatles.members.create(
    ...     name="George Harrison", through_defaults={"date_joined": date(1960, 8, 1)}
    ... )
    >>> beatles.members.set(
    ...     [john, paul, ringo, george], through_defaults={"date_joined": date(1960, 8, 1)}
    ... )

Il peut être préférable de créer directement des instances du modèle intermédiaire.

Si la table intermédiaire personnalisée définie par le modèle intermédiaire ne force pas l’unicité sur la paire `(model1, model2)`, autorisant ainsi des valeurs multiples, l’appel à `remove()` va supprimer toutes les instances de modèles intermédiaires :

    >>> Membership.objects.create(
    ...     person=ringo,
    ...     group=beatles,
    ...     date_joined=date(1968, 9, 4),
    ...     invite_reason="You've been gone for a month and we miss you.",
    ... )
    >>> beatles.members.all()
    <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
    >>> # This deletes both of the intermediate model instances for Ringo Starr
    >>> beatles.members.remove(ringo)
    >>> beatles.members.all()
    <QuerySet [<Person: Paul McCartney>]>

La méthode `clear()` peut être utilisée pour enlever toutes les relations plusieurs-à-plusieurs d’une instance :

    >>> # Beatles have broken up
    >>> beatles.members.clear()
    >>> # Note that this deletes the intermediate model instances
    >>> Membership.objects.all()
    <QuerySet []>

Après avoir établi des relations plusieurs-à-plusieurs, il est possible d’effectuer des requêtes. Comme pour une relation plusieurs-à-plusieurs normale, les requêtes peuvent utiliser les attributs du modèle lié à la relation plusieurs-à-plusieurs :

    # Find all the groups with a member whose name starts with 'Paul'
    >>> Group.objects.filter(members__name__startswith="Paul")
    <QuerySet [<Group: The Beatles>]>

Comme vous utilisez un modèle intermédiaire, la requête peut aussi exploiter ses attributs :

    # Find all the members of the Beatles that joined after 1 Jan 1961
    >>> Person.objects.filter(
    ...     group__name="The Beatles", membership__date_joined__gt=date(1961, 1, 1)
    ... )
    <QuerySet [<Person: Ringo Starr]>

Si vous avez besoin d’accéder aux informations d’appartenance au groupe, c’est possible de le faire en interrogeant directement le modèle `Membership`:

    >>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
    >>> ringos_membership.date_joined
    datetime.date(1962, 8, 16)
    >>> ringos_membership.invite_reason
    'Needed a new drummer.'

Une autre façon d’accéder à la même information est d’interroger la relation plusieurs-à-plusieurs inverse à partir d’un objet `Person`:

    >>> ringos_membership = ringo.membership_set.get(group=beatles)
    >>> ringos_membership.date_joined
    datetime.date(1962, 8, 16)
    >>> ringos_membership.invite_reason
    'Needed a new drummer.'

#### Relations un-à-un

Pour définir une relation un-à-un, utilisez `OneToOneField`. Son utilisation est pareille à celle des autres types de champs `Field`: il s’agit d’un attribut de classe d’un modèle.

Son utilisation principale concerne la clé primaire d’un objet lorsque cet objet « complète » un autre objet d’une certaine manière.

`OneToOneField` exige un paramètre positionnel : la classe à laquelle le modèle est lié.

Par exemple, si vous construisiez une base de données d”« emplacements » (`Place` dans l’exemple), il s’agirait de mettre en place des éléments assez standards comme l’adresse, le numéro de téléphone, etc. dans la base de données. Ensuite, si vous souhaitez construire une base de données de restaurants au-dessus de la base des emplacements, au lieu de vous répéter et de répliquer tous ces champs dans le modèle `Restaurant`, il serait possible de concevoir `Restaurant` avec un champ `OneToOneField` vers `Place` (parce qu’un restaurant « est un » emplacement ; en fait, pour gérer cela, vous feriez probablement appel à de l’héritage, ce qui implique une relation un-à-un implicite).

Comme pour `ForeignKey`, il est aussi possible de créer des relations récursives et des relations vers des modèles non encore définis.

Voir aussi

Consultez les exemples de relations un-à-un entre modèles pour voir un exemple complet.

Les champs `OneToOneField` acceptent aussi un paramètre `parent_link` facultatif.

Précédemment, les classes `OneToOneField` devenaient automatiquement la clé primaire d’un modèle. Cela n’est plus le cas (même si il est toujours possible de passer manuellement le paramètre `primary_key` si vous le voulez). Il est donc possible d’avoir plusieurs champs `OneToOneField` dans un seul modèle.

### Modèles dans plusieurs fichiers

Il est parfaitement admis de lier un modèle à celui d’une autre application. Pour cela, importez le modèle à lier au sommet du fichier où votre modèle est défini. Puis, faites référence à cette autre classe de modèle là où c’est nécessaire. Par exemple :

    from django.db import models
    from geography.models import ZipCode

    class Restaurant(models.Model):
        # ...
        zip_code = models.ForeignKey(
            ZipCode,
            on_delete=models.SET_NULL,
            blank=True,
            null=True,
        )

Il est aussi possible d’utiliser une référence différée au modèle lié, sous forme de chaîne dans le format `"étiquette_app.NomModele"`. Cela ne nécessite pas que le modèle lié soit importé. Par exemple :

    from django.db import models

    class Restaurant(models.Model):
        # ...
        zip_code = models.ForeignKey(
            "geography.ZipCode",
            on_delete=models.SET_NULL,
            blank=True,
            null=True,
        )

Voir liaisons différées pour plus de détails.

### Restrictions sur les noms de champs

Django soumet les noms de champs de modèles à quelques restrictions :

1. Un nom de champ ne peut pas être un mot réservé de Python, car il en résulterait une erreur de syntaxe Python. Par exemple :

       class Example(models.Model):
           pass = models.IntegerField() # 'pass' is a reserved word!

2. Un nom de champ ne peut pas contenir deux soulignements suivis, en raison du fonctionnement de la syntaxe Django pour les requêtes. Par exemple :

       class Example(models.Model):
           foo__bar = models.IntegerField()  # 'foo__bar' has two underscores!

3. Un nom de champ ne peut pas se terminer par un trait de soulignement, pour des raisons semblables.

4. Un champ ne peut pas être nommé `check`, car cela surchargerait la méthode `Model.check()` du système des contrôles.

Ces limites peuvent être contournées, car le nom de champ n’est pas nécessairement égal au nom de la colonne de base de données. Voir l’option `db_column`.

Les mots réservés SQL, comme `join`, `where` ou `select` sont autorisés comme noms de champs de modèle, car Django échappe tous les noms de tables ou de colonnes de base de données dans toutes les requêtes SQL sous-jacentes. Il utilise la syntaxe de guillemets propre au moteur de base de données utilisé.

### Types de champs personnalisés

Si aucun des champs de modèle existants ne convient à vos besoins, ou si vous souhaitez tirer profit d’un type de colonne de base de données plus spécialisé, vous pouvez créer votre propre classe de champ. Une documentation complète sur la création de champs personnalisés se trouve dans Écriture de champs de modèles personnalisés.

## Options de `Meta`

Vous pouvez attribuer des métadonnées à votre modèle en utilisant une classe `Meta` imbriquée, comme ceci :

    from django.db import models

    class Ox(models.Model):
        horn_length = models.IntegerField()

        class Meta:
            ordering = ["horn_length"]
            verbose_name_plural = "oxen"

Les métadonnées de modèles sont « tout ce qui n’est pas un champ », comme les options de tri (`ordering`), le nom de la table de base de données (`db_table`) ou des noms verbeux singulier et pluriel (`verbose_name` et `verbose_name_plural`). Aucune n’est obligatoire et la présence de `class Meta` dans un modèle est entièrement facultative.

Une liste complète de toutes les options `Meta` possibles se trouve dans la référence des options de modèle.

## Les attributs de modèle

`objects`

  L’attribut le plus important d’un modèle est le `Manager`. Il s’agit de l’interface par laquelle les modèles Django ont accès aux opérations de requêtes vers la base de données et par laquelle les instances de modèles sont construites à partir de la base de données. Si aucun objet `Manager` (gestionnaire) personnalisé n’est indiqué, le nom par défaut est `objects`. Les gestionnaires ne sont accessibles qu’au travers des classes de modèle, et pas des instances de modèle.

## Méthodes des modèles

Pour ajouter des fonctionnalités de « niveau ligne » à vos objets, définissez des méthodes personnalisées dans le modèle. Alors que les méthodes de `Manager` sont prévues pour agir au niveau des tables, les méthodes de modèles agissent plutôt sur une instance particulière d’un modèle.

C’est une technique importante pour conserver la logique métier à un seul endroit, le modèle.

Par exemple, ce modèle possède quelques méthodes personnalisées :

    from django.db import models

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        birth_date = models.DateField()

        def baby_boomer_status(self):
            "Returns the person's baby-boomer status."
            import datetime

            if self.birth_date < datetime.date(1945, 8, 1):
                return "Pre-boomer"
            elif self.birth_date < datetime.date(1965, 1, 1):
                return "Baby boomer"
            else:
                return "Post-boomer"

        @property
        def full_name(self):
            "Returns the person's full name."
            return f"{self.first_name} {self.last_name}"

La dernière méthode de cet exemple est une propriété.

La référence des instances de modèles présente une liste complète des méthodes automatiquement héritées par chaque modèle. Vous pouvez surcharger la plupart d’entre elles, voir surcharge des méthodes de modèles prédéfinies ci-dessous, mais vous souhaiterez presque toujours définir certaines dans vos modèles :

`__str__()`

  Une « méthode magique » de Python qui renvoie une représentation textuelle d’un objet. C’est ce que Python et Django utilisent chaque fois qu’une instance de modèle doit être transformée en une simple chaîne en vue d’être affichée. C’est par exemple le cas lorsqu’un objet doit être affiché dans une console interactive ou dans l’interface d’administration.

  Cette méthode devrait toujours être définie ; la valeur par défaut n’est vraiment pas très utile.

`get_absolute_url()`

  Cette méthode indique à Django comment produire l’URL d’un objet. Django l’utilise dans son interface d’administration ainsi qu’à chaque fois qu’il a besoin de connaître l’URL d’un objet.

  Chaque objet possédant un URL permettant de l’identifier de manière unique devrait définir cette méthode.

### Surcharge des méthodes de modèles prédéfinies

Un autre groupe de méthodes de modèles recouvrent un ensemble de comportements liés à la base de données et sont susceptibles d’être personnalisées. En particulier, il est assez fréquent de vouloir modifier le fonctionnement de `save()` et de `delete()`.

Vous êtes libre de surcharger ces méthodes (et toute autre méthode de modèle) pour modifier leur comportement.

Un cas d’utilisation classique de surcharge des méthodes intégrées est lorsque vous souhaitez effectuer une action lors de l’enregistrement d’un objet. Par exemple (voir `save()` pour de la documentation sur les paramètres acceptés) :

    from django.db import models

    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()

        def save(self, **kwargs):
            do_something()
            super().save(**kwargs)  # Call the "real" save() method.
            do_something_else()

Vous pouvez aussi empêcher l’enregistrement :

    from django.db import models

    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()

        def save(self, **kwargs):
            if self.name == "Yoko Ono's blog":
                return  # Yoko shall never have her own blog!
            else:
                super().save(**kwargs)  # Call the "real" save() method.

Il est important de ne pas oublier d’appeler la méthode de la classe parente (c’est l’affaire de `super().save(**kwargs)`) pour s’assurer que l’objet soit bien enregistré dans la base de données. Si vous omettez d’appeler la méthode parente, le comportement par défaut n’est pas appliqué et la base de données ne sera pas affectée.

Il est aussi important de transmettre les paramètres qui peuvent être acceptés par la méthode du modèle, c’est le rôle de `**kwargs`. De temps à autre, Django étend les possibilités des méthodes de modèles intégrées en ajoutant de nouveaux paramètres nommés. Si vous utilisez `**kwargs` dans vos définitions de méthodes, vous êtes certain que votre code gérera automatiquement ces paramètres quand ils seront ajoutés.

Si vous souhaitez mettre à jour un champ dans la méthode `save()`, il peut être nécessaire de devoir aussi ajouter ce champ dans l’argument nommé `update_fields`. Cela garantira que le champ sera bien enregistré dans le cas où `update_fields` est rempli. Par exemple

    from django.db import models
    from django.utils.text import slugify

    class Blog(models.Model):
        name = models.CharField(max_length=100)
        slug = models.TextField()

        def save(self, **kwargs):
            self.slug = slugify(self.name)
            if (
                update_fields := kwargs.get("update_fields")
            ) is not None and "name" in update_fields:
                kwargs["update_fields"] = {"slug"}.union(update_fields)
            super().save(**kwargs)

Voir Indication des champs à enregistrer pour plus de détails.

Les méthodes de modèle surchargées ne sont pas appelées dans les opérations groupées

Note that the `delete()` method for an object is not necessarily called when deleting objects in bulk using a QuerySet or as a result of a cascading delete (see `on_delete`). To ensure customized delete logic gets executed, you can use `pre_delete` and/or `post_delete` signals.

Malheureusement, il n’y a pas de solution possible lors de la `création` ou de la `mise à jour` d’objets en vrac, puisque ni `save()`, ni `pre_save`, ni `post_save` ne sont appelés.

### Exécution de SQL personnalisé

Un autre usage assez fréquent est d’écrire des commandes SQL personnalisées dans les méthodes de modèles et les méthodes au niveau module. Pour plus de détails sur l’utilisation de SQL brut, consultez la documentation sur l’utilisation de SQL brut.

## Héritage de modèle

Dans Django, l’héritage de modèle fonctionne de manière presque identique à l’héritage des classes tel qu’il se pratique en Python, mais les éléments de base présentés au début de cette page sont toujours de mise. Cela signifie que la classe de base doit être une sous-classe de `django.db.models.Model`.

La seule décision qui vous revient est de savoir si vous voulez que les modèles parents soient des modèles à part entière (avec leur propre table de base de données) ou si les parents ne sont que des conteneurs d’informations partagées qui ne seront visibles qu’au travers de leurs modèles enfants.

Il existe trois types d’héritage possibles avec Django.

1. Souvent, vous voulez simplement que la classe parente contienne des informations que vous ne souhaitez pas ressaisir dans chaque modèle enfant. Cette classe ne sera jamais utilisée pour elle-même, il s’agit donc de Classes de base abstraites.

2. Si vous héritez d’un modèle existant (provenant peut-être d’une toute autre application) et que vous souhaitez que chaque modèle dispose de sa propre table de base de données, il s’agit de Héritage multi-table.

3. Finalement, si vous souhaitez uniquement modifier le comportement d’un modèle dans son code Python sans toucher aux champs de modèle, il s’agit de Modèles mandataires.

### Classes de base abstraites

Les classes de base abstraites sont utiles lorsque vous souhaitez regrouper certaines informations communes à un ensemble de modèles. Vous rédigez la classe de base et indiquez `abstract=True` dans sa classe Meta. Aucune table de base de données ne sera créée pour ce modèle. Par contre, lorsqu’elle sera utilisée comme classe de base pour d’autres modèles, ses champs seront ajoutés à ceux de la classe enfant.

Un exemple :

    from django.db import models

    class CommonInfo(models.Model):
        name = models.CharField(max_length=100)
        age = models.PositiveIntegerField()

        class Meta:
            abstract = True

    class Student(CommonInfo):
        home_group = models.CharField(max_length=5)

Le modèle `Student` aura trois champs : `name`, `age` et `home_group`. Le modèle `CommonInfo` ne peut pas être utilisé comme un modèle Django normal, car c’est une classe de base abstraite. Ce modèle ne génère pas de table de base de données et ne possède pas de gestionnaire ; il ne peut pas être instancié ni enregistré directement.

Les champs hérités de classes de base abstraites peuvent être remplacés par un autre champ ou valeur, ou même être enlevés en définissant le nom du champ à `None`.

Dans beaucoup de situations, c’est ce type d’héritage de modèle qui convient. Il offre la possibilité de regrouper les informations communes au niveau Python, tout en ne créant qu’une table de base de données par modèle enfant.

#### Héritage de `Meta`

Lorsqu’une classe de base abstraite est créée, Django rend disponible toute classe imbriquée Meta déclarée dans la classe de base comme attribut. Si une classe enfant ne déclare pas sa propre classe Meta, elle hérite de la classe Meta de son parent. Si la classe enfant souhaite étendre la classe Meta du parent, elle peut en hériter. Par exemple :

    from django.db import models

    class CommonInfo(models.Model):
        # ...
        class Meta:
            abstract = True
            ordering = ["name"]

    class Student(CommonInfo):
        # ...
        class Meta(CommonInfo.Meta):
            db_table = "student_info"

Django effectue une seule modification à la classe Meta d’une classe de base abstraite : avant d’installer l’attribut Meta, il définit `abstract=False`. Cela signifie que les enfants des classes de base abstraites ne deviennent pas automatiquement des classes abstraites elles-mêmes. Pour créer une classe de base abstraite qui hérite d’une autre classe abstraite, il faut définir explicitement `abstract=True` dans la classe fille.

Certains attributs n’ont pas de bonne raison d’être intégrés dans la classe Meta d’une classe de base abstraite. Par exemple, la présence de `db_table` signifierait que toutes les classes enfants (celles qui ne contiennent pas leur propre classe Meta) utiliseraient la même table de base de données, ce qui ne serait certainement pas le comportement souhaité.

En raison du fonctionnement de l’héritage Python, si une classe fille hérite de plusieurs classes de base abstraites, seules les options ref:Meta <meta-options> de la première classe de la liste seront héritées par défaut. Pour hériter des options ref:Meta <meta-options> de plusieurs classes de base abstraites, vous devez déclarer explicitement l’héritage Meta. Par exemple

    from django.db import models

    class CommonInfo(models.Model):
        name = models.CharField(max_length=100)
        age = models.PositiveIntegerField()

        class Meta:
            abstract = True
            ordering = ["name"]

    class Unmanaged(models.Model):
        class Meta:
            abstract = True
            managed = False

    class Student(CommonInfo, Unmanaged):
        home_group = models.CharField(max_length=5)

        class Meta(CommonInfo.Meta, Unmanaged.Meta):
            pass

#### Soyez prudent avec `related_name` et `related_query_name`

Si vous utilisez `related_name` ou `related_query_name` d’un champ `ForeignKey` ou `ManyToManyField`, vous devez toujours indiquer un nom inverse ou un nom de requête unique pour le champ. Cela produirait normalement un problème dans les classes de base abstraites, puisque les champs de cette classe sont inclus dans toutes les classes enfants avec exactement les mêmes valeurs d’attributs (y compris `related_name` et `related_query_name` ) à chaque fois.

Pour contourner ce problème, lorsque vous utilisez `related_name` ou `related_query_name` dans une classe de base abstraite (et dans ce cas seulement), des parties de la valeur doivent contenir `'%(app_label)s'` et `'%(class)s'`.

- `'%(class)s'` est remplacé par le nom en minuscules de la classe enfant dans laquelle est utilisé le champ.

- `'%(app_label)s'` est remplacé par le nom en minuscules de l’application dans laquelle la classe enfant est contenue. Chaque nom d’application installée doit être unique et les noms de classes de modèles dans chaque application doivent également être uniques, il est donc garanti que le nom résultant sera chaque fois différent.

Par exemple, étant donné une application `common/models.py`:

    from django.db import models

    class Base(models.Model):
        m2m = models.ManyToManyField(
            OtherModel,
            related_name="%(app_label)s_%(class)s_related",
            related_query_name="%(app_label)s_%(class)ss",
        )

        class Meta:
            abstract = True

    class ChildA(Base):
        pass

    class ChildB(Base):
        pass

Accompagnée d’une autre application `rare/models.py`:

    from common.models import Base

    class ChildB(Base):
        pass

Le nom inverse du champ `common.ChildA.m2m` sera `common_childa_related`, et le nom de requête inverse sera `common_childas`. Le nom inverse du champ `common.ChildB.m2m` sera `common_childb_related` et le nom de requête inverse sera `common_childbs`. Finalement, le nom inverse du champ `rare.ChildB.m2m` sera `rare_childb_related` et le nom de requête inverse sera `rare_childbs`. Vous êtes libre de choisir comment utiliser les portions `'%(class)s'` et `'%(app_label)s'` pour construire le nom lié ou le nom de requête lié, mais si vous oubliez de les inclure, Django signalera des erreurs lors du lancement des vérifications systèmes (ou en lançant `migrate`).

Si vous n’indiquez pas d’attribut `related_name` pour un champ d’une classe de base abstraite, le nom inverse par défaut sera le nom de la classe enfant suivi par `'_set'`, comme cela se serait produit si vous aviez directement déclaré le champ dans la classe enfant. Par exemple, dans le code ci-dessus, si l’attribut `related_name` avait été omis, le nom inverse du champ `m2m` aurait été `childa_set` dans le cas `ChildA` et `childb_set` pour le champ `ChildB`.

### Héritage multi-table

Le deuxième type d’héritage de modèle pris en charge par Django est lorsque chaque modèle d’une hiérarchie est lui-même un modèle à part entière. À chaque modèle correspond une table de base de données qui peut être interrogée et créée individuellement. Cette relation d’héritage introduit des liens entre le modèle enfant et chacun de ses parents (via un champ `OneToOneField` automatique). Par exemple :

    from django.db import models

    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)

    class Restaurant(Place):
        serves_hot_dogs = models.BooleanField(default=False)
        serves_pizza = models.BooleanField(default=False)

Tous les champs de `Place` seront aussi disponible dans `Restaurant`, même si les données se trouveront dans des tables de base de données différentes. Ainsi, ces deux formes sont possibles :

    >>> Place.objects.filter(name="Bob's Cafe")
    >>> Restaurant.objects.filter(name="Bob's Cafe")

Si vous avez une `Place` qui est aussi un `Restaurant`, vous pouvez accéder à l’objet `Restaurant` depuis l’objet `Place` en utilisant le nom du modèle en minuscules :

    >>> p = Place.objects.get(id=12)
    # If p is a Restaurant object, this will give the child class:
    >>> p.restaurant
    <Restaurant: ...>

Cependant, si dans l’exemple ci-dessus `p` n’était pas un `Restaurant` (soit parce qu’il a été créé directement comme un objet `Place` ou qu’il est le parent d’une autre classe), l’accès à `p.restaurant` aurait généré une exception `Restaurant.DoesNotExist`.

Le champ `OneToOneField` automatiquement créé pour `Restaurant` qui le lie à `Place` ressemble à ceci :

    place_ptr = models.OneToOneField(
        Place,
        on_delete=models.CASCADE,
        parent_link=True,
        primary_key=True,
    )

Il est possible de surcharger ce champ en déclarant votre propre `OneToOneField` avec `parent_link=True` dans la classe `Restaurant`.

#### `Meta` et l’héritage multi-table

Dans le cas de l’héritage multi-table, l’héritage de la classe Meta du parent n’a aucun intérêt pour la classe enfant. Toutes les options Meta ont déjà été appliquées à la classe parente et une nouvelle application n’amènerait qu’à des comportements contradictoires (a contrario du cas de la classe de base abstraite où la classe de base n’existe pas pour elle-même).

Ainsi, un modèle enfant n’a pas accès à la classe Meta de son parent. Cependant, il existe quelques cas limités où l’enfant hérite du comportement de son parent : si l’enfant n’indique pas d’attribut `ordering` ou `get_latest_by`, il hérite des attributs correspondants de son parent.

Si le parent possède un ordre de tri mais que vous ne souhaitez pas que l’enfant ait un ordre de tri quelconque, vous pouvez le désactiver explicitement :

    class ChildModel(ParentModel):
        # ...
        class Meta:
            # Remove parent's ordering effect
            ordering = []

#### Héritage et relations inverses

Comme l’héritage multi-table utilise un champ `OneToOneField` implicite pour lier l’enfant à son parent, il est possible d’accéder à l’enfant depuis le parent comme dans l’exemple ci-dessus. Cependant, il est fait usage du nom correspondant à la valeur par défaut de `related_name` pour les relations `ForeignKey` and `ManyToManyField`. Si vous ajoutez ces types de relations dans la sous-classe du modèle parent, vous devez renseigner l’attribut `related_name` pour chacun de ces champs. Si vous l’oubliez, Django génère une erreur de validation.

Par exemple, en se basant toujours sur la classe `Place` ci-dessus, créons une autre sous-classe avec un champ `ManyToManyField`:

    class Supplier(Place):
        customers = models.ManyToManyField(Place)

Il en résulte une erreur :

    Reverse query name for 'Supplier.customers' clashes with reverse query
    name for 'Supplier.place_ptr'.

    HINT: Add or change a related_name argument to the definition for
    'Supplier.customers' or 'Supplier.place_ptr'.

L’ajout de `related_name` au champ `customers` comme ci-après permettrait de résoudre l’erreur : `models.ManyToManyField(Place, related_name='provider')`.

#### Indication du champ de lien vers le parent

Comme déjà mentionné, Django crée automatiquement une relation `OneToOneField` de la classe enfant vers tout modèle parent non abstrait. Si vous souhaitez contrôler le nom du champ de liaison vers le parent, vous pouvez ajouter votre propre champ `OneToOneField` et définir `parent_link=True` pour indiquer que ce champ est le champ de liaison vers la classe parente.

### Modèles mandataires

Lorsqu’on utilise l’héritage multi-table, une nouvelle table de base de données est créée pour chaque sous-classe d’un modèle. C’est normalement le comportement souhaité, dans la mesure où la sous-classe doit pouvoir stocker les champs de données supplémentaires qui ne figurent pas dans la classe de base. Cependant, dans certains cas, seul le comportement Python d’un modèle a besoin d’être modifié, peut-être pour changer le gestionnaire par défaut ou pour ajouter une nouvelle méthode.

C’est l’objectif de l’héritage de modèle mandataire : créer un mandataire (« proxy ») du modèle d’origine. Vous pouvez créer, supprimer et mettre à jour des instances du modèle mandataire et toutes les données seront enregistrées comme si vous utilisiez le modèle d’origine (non mandataire). La différence est que vous pouvez modifier certaines choses dans le modèle mandataire comme le tri par défaut des modèles ou le gestionnaire par défaut, sans devoir toucher au modèle original.

Les modèles mandataires sont déclarés comme des modèles normaux. Vous indiquez à Django qu’il s’agit de modèles mandataires en définissant l’attribut `proxy` de la classe `Meta` à `True`.

Par exemple, supposons que vous vouliez ajouter une méthode au modèle `Person`. Vous pouvez le faire de cette façon :

    from django.db import models

    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)

    class MyPerson(Person):
        class Meta:
            proxy = True

        def do_something(self):
            # ...
            pass

La classe `MyPerson` opère sur la même table de base de données que sa classe parente `Person`. En particulier, toute nouvelle instance de `Person` sera aussi accessible au travers de `MyPerson` et inversement :

    >>> p = Person.objects.create(first_name="foobar")
    >>> MyPerson.objects.get(first_name="foobar")
    <MyPerson: foobar>

Il est aussi possible d’utiliser un modèle mandataire pour définir un autre tri par défaut sur un modèle. Par exemple, vous ne voulez pas toujours trier le modèle `Person`, mais souvent le trier par `last_name` lorsque que vous utilisez le mandataire :

    class OrderedPerson(Person):
        class Meta:
            ordering = ["last_name"]
            proxy = True

Dorénavant les requêtes sur `Person` ne seront pas triées mais les requêtes sur `OrderedPerson` seront triées par leur champ `last_name`.

Les modèles mandataires héritent des attributs `Meta` tout comme les modèles normaux.

#### Les requêtes `QuerySet` renvoient toujours le modèle interrogé

Il n’y a aucun moyen de demander à Django de renvoyer par exemple un objet `MyPerson` chaque fois que vous faites une requête sur des objets `Person`. Une requête sur des objets `Person` renvoie toujours des objets de ce même type. L’idée principale des objets mandataires est que le code se basant sur l’objet `Person` original utilise ces objets-là et que votre propre code peut utiliser les extensions que vous avez rajoutées (et qu’aucun autre code ne peut utiliser de toute manière). Ce n’est pas une façon de remplacer partout le modèle `Person` (ou un autre) par un autre modèle de votre conception.

#### Restrictions des classes de base

Un modèle mandataire ne peut hériter que d’une seule classe de modèle non abstraite. Il n’est pas possible d’hériter de plusieurs modèles non abstraits car le modèle mandataire ne fournit aucune connexion entre les lignes de différentes tables de base de données. Un modèle mandataire peut hériter d’autant de classes de modèle abstraites que nécessaire pourvu qu’elles ne définissent pas de champ de modèle. Un modèle mandataire peut aussi hériter de plusieurs autres modèles mandataires qui partagent une classe parente non abstraite commune.

#### Gestionnaires des modèles mandataires

Si vous n’indiquer aucun gestionnaire de modèle pour un modèle mandataire, il hérite des gestionnaires de ses modèles parents. Si vous définissez un gestionnaire sur le modèle mandataire, il devient le gestionnaire par défaut, bien que d’éventuels gestionnaires définis dans les classes parentes seront aussi disponibles.

En poursuivant l’exemple ci-dessus, vous pourriez modifier le gestionnaire par défaut utilisé lors des requêtes sur le modèle `Person` comme ceci :

    from django.db import models

    class NewManager(models.Manager):
        # ...
        pass

    class MyPerson(Person):
        objects = NewManager()

        class Meta:
            proxy = True

Si vous souhaitez ajouter un nouveau gestionnaire au modèle mandataire sans remplacer celui qui est défini par défaut, vous pouvez employer les techniques décrites dans la documentation des gestionnaires personnalisés : créez une classe de base contenant les nouveaux gestionnaires et héritez de celle-ci après la classe de base principale :

    # Create an abstract class for the new manager.
    class ExtraManagers(models.Model):
        secondary = NewManager()

        class Meta:
            abstract = True

    class MyPerson(Person, ExtraManagers):
        class Meta:
            proxy = True

Il est assez rare d’avoir besoin de le faire, mais si besoin est, c’est possible.

#### Différences entre l’héritage mandataire et les modèles non pilotés

L’héritage des modèles mandataires est en apparence très semblable à la création de modèles non pilotés, utilisant l’attribut `managed` de la classe `Meta` d’un modèle.

En définissant soigneusement `Meta.db_table`, il est possible de créer un modèle non piloté masquant un modèle existant et d’y ajouter des méthodes Python. Cependant, cette solution est très répétitive et fragile dans la mesure où il faut manuellement synchroniser les deux en cas de modifications.

D’un autre côté, les modèles mandataires sont conçus pour se comporter exactement comme le modèle qu’ils étendent. Ils sont toujours synchronisés avec le modèle parent car ils héritent directement de ses champs et de ses gestionnaires.

Les règles générales sont :

1. Si vous reflétez un modèle ou une table de base de données existant et que vous ne souhaitez pas reproduire toutes les colonnes d’origine de la table, utilisez `Meta.managed=False`. Cette option est habituellement utile pour la modélisation de tables ou vues de base de données qui ne sont pas sous le contrôle de Django.

2. Si votre objectif est de ne modifier que le comportement Python d’un modèle tout en conservant les mêmes champs que l’original, utilisez `Meta.proxy=True`. Cette configuration assure que le modèle mandataire est une copie exacte de la structure de stockage du modèle de base lorsque des données sont enregistrées.

### Héritage multiple

Tout comme l’héritage en Python, les modèles Django peuvent hériter de plusieurs modèles parents. N’oubliez pas que les règles Python habituelles de résolution de nom s’appliquent. La première classe de base dans laquelle apparaît un nom particulier (par ex. Meta) prévaut sur les autres apparitions ; par exemple, cela signifie que si plusieurs parents contiennent une classe Meta, seule la première occurrence sera utilisée, et toutes les autres seront ignorées.

Généralement, il ne devrait pas être nécessaire d’hériter de plusieurs parents. La principale raison de le faire est dans le cas de classes « mix-in » : l’ajout d’un champ supplémentaire particulier ou d’une méthode dans chaque classe héritant de la classe « mix-in ». Essayez de garder votre hiérarchie d’héritage aussi simple et compréhensible que possible afin de ne pas devoir batailler au moment de retrouver la provenance d’une information ou d’un comportement spécifique.

Notez qu’en héritant de plusieurs modèles possédant un champ de clé primaire `id` commun, une erreur sera signalée. Pour un héritage multiple correct, vous pouvez utiliser un champ `AutoField` explicite dans les modèles de base :

    class Article(models.Model):
        article_id = models.AutoField(primary_key=True)
        ...

    class Book(models.Model):
        book_id = models.AutoField(primary_key=True)
        ...

    class BookReview(Book, Article):
        pass

Ou utilisez un ancêtre commun pour contenir la classe `AutoField`. Cela nécessite l’utilisation explicite de `OneToOneField` pour chaque modèle parent vers l’ancêtre commun pour éviter un conflit entre les champs générés automatiquement et hérités par l’enfant

    class Piece(models.Model):
        pass

    class Article(Piece):
        article_piece = models.OneToOneField(
            Piece, on_delete=models.CASCADE, parent_link=True
        )
        ...

    class Book(Piece):
        book_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)
        ...

    class BookReview(Book, Article):
        pass

### Le masquage de nom de champ n’est pas autorisé

Dans l’héritage habituel de classes Python, il est permis de surcharger n’importe quel attribut de la classe parent par la classe enfant. Avec Django, cela n’est généralement pas permis pour les champs de modèle. Si une classe de base de modèle non abstraite possède un champ `auteur`, il n’est pas possible de créer un autre champ de modèle ou de définir un attribut nommé `auteur` dans les classes qui héritent de cette classe de base.

Cette restriction ne s’applique pas aux champs de modèle hérités d’un modèle abstrait. De tels champs peuvent être remplacés avec un autre champ ou valeur, ou même être enlevés en définissant `nom_de_champ = None`.

Avertissement

Les gestionnaires de modèle sont hérités des classes de base abstraites. La surcharge d’un champ hérité qui est référencé par un `Manager` hérité peut causer des anomalies subtiles. Voir gestionnaires personnalisés et héritage de modèles.

Note

Certains champs définissent des attributs supplémentaires sur les modèles, par ex. une clé `ForeignKey` définit un attribut supplémentaire formé du nom de champ ajouté du suffixe `_id`, ainsi que des valeurs `related_name` et `related_query_name` sur le modèle associé.

Ces attributs supplémentaires ne peuvent pas être remplacés sans que le champ qui les définit soit modifié ou enlevé pour qu’il ne définisse plus ces attributs.

La surcharge de champs de modèles parents pose des problèmes dans les domaines de l’initialisation de nouvelles instances (pour indiquer quel champ est initialisé dans `Model.__init__`) et de la sérialisation. Ce sont des situations qui n’affectent pas de la même manière l’héritage habituel de classes Python, cette différence entre l’héritage des classes Python et l’héritage des modèles Django n’est donc pas arbitraire.

Cette restriction ne s’applique qu’aux attributs qui sont des instances de `Field`. Les attributs Python normaux peuvent être surchargés sans problème. Cela ne s’applique aussi qu’au nom de l’attribut tel que Python le voit : si vous indiquez manuellement le nom de la colonne de base de données, il est possible d’avoir le même nom de colonne apparaissant à la fois dans un enfant et son modèle parent dans de l’héritage multi-table (ce sont finalement des colonnes appartenant à deux tables de base de données différentes).

Django signale une erreur `FieldError` si vous surchargez un champ de modèle d’une classe parente.

Notez qu’en raison de la manière dont les champs sont résolus durant la définition de classe, les champs de modèles hérités de plusieurs modèles parents abstraits sont résolus dans un ordre strict de parcours en profondeur. Cela contraste avec la stratégie MRO standard de Python, qui est résolue par un parcours en largeur dans les cas d’héritage en diamant. Cette différence n’affecte que les hiérarchies complexes de modèles, lesquelles devraient être évitées (selon le conseil ci-dessus).

## Organisation des modèles en paquets

La commande `manage.py startapp` crée une structure d’application qui inclut un fichier `models.py`. Si vous avez beaucoup de modèles, il peut être avantageux de les organiser en fichiers séparés.

Pour ce faire, créez un paquet `models`. Effacez `models.py` et créez un répertoire `mon_app/models/` contenant un fichier `__init__.py` ainsi que les fichiers stockant les modèles. Vous devez importer les modèles dans le fichier `__init__.py`.

Par exemple, si vous avez `organic.py` et `synthetic.py` dans le répertoire `models`:

`myapp/models/__init__.py`

    from .organic import Person
    from .synthetic import Robot

L’importation explicite de chaque modèle plutôt que d’importer en vrac `from .models import *` possède les avantages de ne pas polluer l’espace de noms, de rendre le code plus lisible et de faciliter le travail des outils d’analyse de code.

Voir aussi

La référence des modèles

  Documente toutes les API liées aux modèles, y compris les champs de modèles, les objets liés et les requêtes (`QuerySet`).