Django-fr | Documentation | Document de référence des modèles

Django-fr

Documentation Django

Document de référence des modèles

Un modèle est une description unique et définitive de vos données. Il contient les champs et comportements 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 étend django.db.models.Model.
  • Chaque attribut du modèle représente un champ de base de données.
  • Les méta-données du modèle (informations n'étant pas des champs) vont dans une classe interne nommée Meta.
  • Les méta-données utilisées pour le site d'administration de Django vont dans une classe interne nommée Admin.
  • Avec tout cela, Django vous donne une API d'accès à la base de données générée automatiquement, qui est décrite dans la Documentation de référence pour l'API de base de données.

Pour accompagner ce document, n'hésitez pas à jeter un œil au dépôt officiel des exemples de modèle. (Dans le paquetage des sources de Django, ces exemples sont dans le répertoire tests/modeltests.)

Exemple rapide

Ce modèle d'exemple définit une Personne, qui possède un prenom et un nom:

from django.db import models

class Personne(models.Model):
    prenom = models.CharField(maxlength=30)
    nom = models.CharField(maxlength=30)

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

Le modèle Personne ci-dessus créerait une table de base de données comme celle-ci:

CREATE TABLE monappli_personne (
    "id" serial NOT NULL PRIMARY KEY,
    "prenom" varchar(30) NOT NULL,
    "nom" varchar(30) NOT NULL
);

Quelques notes techniques:

  • Le nom de la table, monappli_personne, est automatiquement dérivé de quelques méta-données du modèle mais peut être personnalisé. Lisez Noms de table un peu plus bas.
  • Un champ id est ajouté automatiquement, mais ce comportement peut être modifié. Lisez Les champs de clé primaire automatiques plus bas.
  • Le code SQL CREATE TABLE de cet exemple est formaté en utilisant la syntaxe de PostgreSQL, mais il est bon de noter que Django adapte son code SQL au backend de la base de données spécifiée dans votre fichier de configuration.

Les champs

La partie la plus importante d'un modèle -- et la seule partie requise d'un modèle -- est la liste des champs de base de données qu'il définit. Les champs sont définis par attributs de classe.

Par exemple:

class Musicien(models.Model):
    prenom = models.CharField(maxlength=50)
    nom = models.CharField(maxlength=50)
    instrument = models.CharField(maxlength=100)

class Album(models.Model):
    artiste = models.ForeignKey(Musicien)
    nom = models.CharField(maxlength=100)
    date_de_sortie = models.DateField()
    nb_etoiles = models.IntegerField()

Restrictions des noms de champ

Django place seulement deux restrictions sur les noms de champs d'un modèle:

  1. Un nom de champ ne peut pas être un mot réservé du langage Python, parce que cela produirait une erreur de syntaxe Python. Par exemple:

    class Exemple(models.Model):
        pass = models.IntegerField() # 'pass' est un mot réservé !
    
  2. Un nom de champ ne peut pas contenir plusieurs underscores consécutifs, à cause de la manière dont fonctionne la syntaxe de requête de recherche dans Django. Par exemple:

    class Exemple(models.Model):
        foo__bar = models.IntegerField() 'foo__bar' a deux underscores !
    

Ces limitations peuvent être contournées car votre nom de champ de doit pas nécessairement correspondre au nom de colonne de votre base de données. Lisez db_column plus bas.

Les mots réservés du SQL, tels que join, where ou select, sont permis comme noms de champ du modèle, parce que Django échappe tous les noms de table et colonne de base de données dans toutes les requêtes en SQL. Il utilise la syntaxe entre guillemets adaptée à votre moteur de base de données.

Les types de champ

Chaque champ de votre modèle devrait être une instance de la classe Field appropriée. Django utilise les types de classe de champs pour déterminer quelques points:

  • Le type de la colonne de base de données (par exemple, INTEGER, VARCHAR).
  • Le widget à utiliser dans l'interface d'administration de Django, si vous envisagez de l'utiliser (par exemple, <input type="text">, <select>).
  • La validation minimale des données saisies dans le site d'admin de Django et dans les manipulateurs.

Voici tout les types de champs disponibles:

AutoField

C'est un IntegerField qui s'incrémente automatiquement selon les IDs disponibles. Vous aurez rarement à l'utiliser directement ; un champ de clé primaire sera automatiquement ajouté à votre modèle si vous ne spécifiez pas une instruction contraire. Lisez les Les champs de clé primaire automatiques.

BooleanField

Un champs vrai/faux.

L'interface d'admin le représente par une boîte de choix (checkbox).

CharField

Un champ de chaîne de caractères, pour les chaînes courtes comme longues.

Pour les très longues chaînes de texte, préférez plutôt TextField.

L'interface d'admin le représente par un <input type="text"> (une entrée à simple ligne).

CharField possède un argument supplémentaire requis, maxlength, la longueur maximale (en caractères) du champ. Le maxlength est imposé au niveau base de données et est utilisé par Django pour la validation.

CommaSeparatedIntegerField

Un champ de nombres entiers séparés par des virgules. Comme dans CharField, l'argument maxlength est requis.

DateField

Un champ de date. Possède quelques arguments supplémentaires facultatifs:

Argument Description
auto_now Définit automatiquement le champ à la date courante à chaque fois que l'objet est enregistré. Utile pour les champs « dernière-modif ». Notez que la date actuelle est toujours utilisée ; ce n'est pas seulement une valeur par défaut que vous pourriez modifier.
auto_now_add Définit automatiquement le champ à la date courante quand l'objet est créé la première fois. Utile pour contenir les dates de création. Notez que la date actuelle est toujours utilisée ; ce n'est pas seulement une valeur par défaut que vous pourriez modifier.

L'interface d'admin le représente par un <input type="text"> avec un calendrier JavaScript et un raccourci pour « Aujourd'hui ».

DateTimeField

Un champ de date et heure. Prend les mêmes options supplémentaires que DateField.

L'interface d'admin le représente par deux champs <input type="text">, avec des raccourcis JavaScript.

EmailField

Un CharField qui vérifie que la valeur est une adresse de courrier électronique valide. maxlength n'est pas accepté.

FileField

Un champ d'envoi de fichier.

Possède un argument supplémentaire obligatoire, upload_to, définissant un chemin local du système de fichiers où les fichiers reçus devraient être conservés. Ce chemin peut contenir du formatage strftime (en), qui sera remplacé par la date et/ou l'heure où le fichier est reçu (ainsi ces fichiers reçus ne remplissent pas un répertoire donné).

L'interface d'admin le représente par un <input type="file"> (un widget d'envoi de fichier).

Utiliser un FileField ou un ImageField (voir ci-dessous) dans un modèle requiert quelques étapes:

  1. Dans votre fichier de configuration, vous aurez besoin de définir MEDIA_ROOT avec le chemin absolu vers un répertoire où vous aimeriez que Django stocke les fichiers reçus. (Pour des raisons de performance, ces fichiers ne sont pas stockés dans la base de données.) Définissez MEDIA_URL avec l'URL de base publique représentant ce répertoire. Assurez-vous que ce répertoire a les droits en écriture pour le compte utilisateur de celui qui lance le serveur Web.
  2. Ajoutez le FileField ou le ImageField dans votre modèle, assurez-vous de définir l'option upload_to pour dire à Django dans quel sous-répertoire de MEDIA_ROOT il devrait conserver les fichiers reçus.
  3. Tout ce qui sera stocké dans la base de données sera un chemin vers le fichier (relativement à MEDIA_ROOT). Vous aurez certainement à utiliser la fonction utilitaire get_<fieldname>_url fournie par Django. Par exemple, si votre ImageField s'appelle mug_shot, vous pouvez obtenir l'URL absolue de votre image dans un template avec {{ object.get_mug_shot_url }}.

FilePathField

Un champ dont les choix sont limités aux noms de fichier d'un certain répertoire du système de fichiers. Possède trois arguments spéciaux, dont le premier est requis:

Argument Description
path Obligatoire. Le chemin absolu du système de fichiers d'un répertoire dans lequel ce FilePathField est censé générer ses choix. Par exemple: "/home/images".
match Facultatif. Une expression rationnelle, sous forme de chaîne de caractères, que FilePathField utilisera pour filtrer les noms de fichier. Notez que cette regex sera appliquée au nom de base du fichier, et non au chemin complet. Par exemple: "foo.*\.txt^", qui va garder un fichier nommé foo23.txt mais pas bar.txt ni foo23.gif.
recursive Facultatif. Soit True, soit False. False par défaut. Spécifie si tous les sous-répertoires de path devraient être inclus.

Bien-sûr, ces trois arguments peuvent être utilisés ensemble.

Une grande source d'erreur potentielle vient du fait que match s'applique sur le nom de base du fichier, et non sur le chemin complet. Donc, cet exemple:

FilePathField(path="/home/images", match="foo.*", recursive=True)

...va garder /home/images/foo.gif mais pas /home/images/foo/bar.gif parce que le match s'appliquera sur le nom de base du fichier (foo.gif et bar.gif).

FloatField

Un nombre à virgule flottante. Possède deux arguments obligatoires:

Argument Description
max_digits Le nombre maximal de chiffres permis dans le nombre.
decimal_places Le nombre de décimales après la virgule pour stocker le nombre.

Par exemple, pour stocker des nombres jusqu'à 999 avec une résolution de 2 chiffres après la virgule, vous utiliseriez:

models.FloatField(..., max_digits=5, decimal_places=2)

Et poour stocker des nombres jusqu'à approximativement un milliard avec une résolution de 10 chiffres après la virgule:

models.FloatField(..., max_digits=19, decimal_places=10)

L'interface d'admin le représente par un <input type="text"> (une entrée à une seule ligne).

ImageField

Comme FileField, mais contrôle que l'objet reçu est une image valide. Possède deux arguments supplémentaires facultatifs, height_field et width_field, qui, si définis, auto-redimensionneront à la largeur et hauteur donnée l'image à chaque fois que l'intance de modèle est sauvegardée.

Requiert la Bibliothèque d'Imagerie Python - PIL (en).

IntegerField

Un entier.

L'interface d'admin le représente par un <input type="text"> (une entrée à une seule ligne).

IPAddressField

Une adresse IP, dans son format de chaîne de caractères (c'est-à-dire "24.124.1.30").

L'interface d'admin le représente par un <input type="text"> (une entrée à une seule ligne).

NullBooleanField

Comme un BooleanField, sauf qu'il admet NULL comme un des choix. Utilisez cela à la place d'un BooleanField avec null=True.

L'interface d'admin le représente par une boîte <select> avec les choix "Inconnu", "Oui" et "Non".

PasswordField

Un PasswordField est comme un TextField à part que les caractères entrés sont masqués, typiquement par une astérisque (*), lorsqu'ils sont saisis dans un formulaire. Notez que même si la donnée est masquée en entrée, elle est envoyée en texte clair au serveur et stocké en plein texte dans la base de données. Des mesures supplémentaires (telles que l'usage de HTTPS) sont nécessaires pour assurer la sécurité des données envoyées depuis un formulaire. Ce champ est probablement plus utile lorsqu'il est employé dans un manipulateur personnalisé et non directement dans un modèle.

PhoneNumberField

Un CharField qui vérifie que la valeur est un numéro de téléphone américain valide (au format XXX-XXX-XXXX).

PositiveIntegerField

Comme un IntegerField, sauf qu'il doit être positif.

PositiveSmallIntegerField

Comme un PositiveIntegerField, à part qu'il admet seulement les valeurs inférieures à une certaine limite (qui dépend de la base de données).

SlugField

« Slug » est un terme anglophone employé dans le jargon de la publication. Un slug est un court libellé pour désigner quelque chose, contenant seulement des lettres, des nombres, des underscores ou des traits d'union. Ils sont généralement utilisés dans les URLs.

Dans la version en développement de Django, vous pouvez spécifier maxlength. Si maxlength n'est pas spécifié, Django utilisera une longueur par défaut de 50. Dans les versions précédentes de Django, il n'est pas possible de modifier la longueur de 50.

Implique que db_index=True.

Accepte une option supplémentaire, prepopulate_from, qui est une liste de champs depuis laquelle on peut auto-générer le slug, via JavaScript, dans le formulaire de description d'un objet de l'interface d'admin:

models.SlugField(prepopulate_from=("prenom", "nom"))

prepopulate_from n'accepte pas les DateTimeFields.

L'interface d'admin représente un SlugField par un <input type="text"> (une entrée à une seule ligne).

SmallIntegerField

Comme un IntegerField, à part qu'il admet seulement les valeurs inférieures à une certaine limite (qui dépend de la base de données).

TextField

Un champ de texte long.

L'interface d'admin le représente par un <textarea> (une entrée à lignes multiples).

TimeField

Une heure. Accepte les mêmes options d'auto-définition que DateField et DateTimeField.

L'interface d'admin le représente par un <input type="text"> avec quelques raccourcis JavaScript.

URLField

Un champ pour une URL. Si l'option verify_exists est à True (par défaut), l'existence de l'URL donnée sera vérifiée (c'est-à-dire que l'URL charge et ne renvoie pas une réponse 404).

L'interface d'admin le représente par un <input type="text"> (une entrée à une seule ligne).

USStateField

Une abbréviation de deux lettres désignant un état américain.

L'interface d'admin le représente par un <input type="text"> (une entrée d'une seule ligne).

XMLField

Un TextField qui vérifie que la valeur est du XML valide qui correspond au schéma donné. Prend un argument obligatoire, schema_path, qui est un chemin du système de fichier vers un schéma RelaxNG à partir duquel le champ sera contrôlé.

Les options de champ

Les arguments suivants sont disponibles pour tous les types de champ. Ils sont tous facultatifs.

null

S'il est mis à True, Django stockera les valeurs vides comme des NULL dans la base de données. Par défaut, False.

Notez que les valeurs de chaîne vide seront toujours stockées sous forme de chaînes vides, et non en tant que NULL -- donc utilisez null=True pour les champs qui ne sont pas des chaînes de caractères, tels que les entiers, les booléens et les dates.

Inutile d'utiliser null sur les champs basés sur des chaînes de caractères, tels que CharField et TextField, sauf si vous avez une excellente raison. Si un champ basé sur des chaînes de caractères possède l'option null=True, cela signifie qu'il y a deux valeurs possibles pour "pas de données": NULL, et la chaîne vide. Dans la plupart des cas, il est redondant d'avoir deux valeurs possibles pour "pas de donnée"; la convention adoptée par Django est d'utiliser la chaîne vide plutôt que NULL.

blank

S'il est mis à True, on permet que le champ soit vide.

Notez que celui-ci est différent de null. null est purement lié à la base de données, alors que blank est lié au contrôle de la validité de la saisie. Si un champ a l'option blank=True, le système de validation dans le site d'admin de Django autorisera la saisie de valeur vide. Si un champ a l'option blank=False, le champ sera obligatoire.

choices

Une séquence itérable (par exemple, une liste ou un tuple) constitué de 2-tuples qui seront utilisé comme liste à choix multiples pour ce champ.

Si cette option est donnée, l'interface d'admin de Django utilisera une boîte de sélection au lieu du champ de texte standard et limitera les choix aux choix donnés.

Une liste à choix multiples ressemble à ceci:

GRADES_ECOLE_SPORTIVE = (
    ('PS', 'Poussin'),
    ('MN', 'Minime'),
    ('JR', 'Junior'),
    ('SR', 'Sénior'),
    ('VT', 'Vétéran'),
)

Le premier élément de chaque tuple est la valeur qui sera en fait stockée. Le second élément est la définition qui sera affichée à l'utilisateur pour ce choix-là.

Les listes à choix multiples peuvent être aussi bien définies à l'intérieur de votre classe de modèle:

class Toto(models.Model):
    LISTE_GENRES = (
        ('H', 'Homme'),
        ('F', 'Femmme'),
    )
    genre = models.CharField(maxlength=1, choices=LISTE_GENRES)

Qu'à l'extérieur de votre classe de modèle:

LISTE_GENRES = (
    ('H', 'Homme'),
    ('F', 'Femme'),
)
class Toto(models.Model):
    genre = models.CharField(maxlength=1, choices=LISTE_GENRES)

Enfin, notez que ces choix peuvent être n'importe quel objet itérable -- pas nécessairement une liste ou un tuple. Cela vous permet de construire des listes à choix multiples dynamiquement. Mais si vous vous retrouvez à coder les objets que vous passez dans choices pour être dynamique, il serait probablement mieux que vous utilisiez une table de base de données à part avec une clé étrangère ForeignKey. choices est censé être utilisé pour de la donnée statique qui ne change plus.

core

Pour des objets qui sont édités à l'intérieur d'un objet lié.

Dans l'interface d'admin de Django, si tous les champs « core » dans un objet édité imbriqué sont vides, alors cet objet est supprimé.

Une erreur est déclenchée si on a une relation d'édition imbriquée sans au moins un champ core=True.

Merci de noter que chaque champ marqué "core" est traité comme un champ requis par le site d'admin de Django. En particulier, cela signifie que vous devriez mettre core=True sur tout les champs obligatoire dans votre objet lié qui est édité à l'intérieur d'un autre.

db_column

Le nom de la colonne de base de données à utiliser pour ce champ. S'il n'est pas fourni, Django utilisera le nom du champ.

Si votre nom de colonne est un mot réservé du langage SQL, ou s'il contient des caractères qui ne sont pas permis dans les noms de variable Python -- notamment, le trait d'union -- c'est bon. Django met entre guillemets les noms de tables et de colonnes de manière transparente.

db_index

S'il est mis à True, django-admin.py sqlindexes affichera une instruction CREATE INDEX pour ce champ.

default

La valeur par défaut du champ.

editable

S'il est mis à False, le champ ne sera pas éditable dans l'interface d'admin. Par défaut, True.

help_text

Un texte d'aide supplémentaire à afficher sous le champ dans le formulaire d'édition d'un objet de l'interface d'admin. C'est utile pour la documentation, même si votre objet n'a pas de formulaire d'administration.

primary_key

S'il est mis à True, ce champ est la clé primaire du modèle.

Si vous ne spécifiez primary_key=True pour aucun champ de votre modèle, Django ajoutera automatiquement ce champ:

id = models.AutoField('ID', primary_key=True)

Ainsi, vous n'avez pas besoin de définir primary_key=True sur l'un de vos champs, sauf si voulez changer ce comportement par défaut de clé primaire.

primary_key=True implique blank=False, null=False et unique=True. Seule une clé primaire est permise par objet.

radio_admin

Par défaut, l'interface d'admin de Django utilise la boîte de sélection (<select>) pour les champs de clé étrangère ForeignKey ou qui ont l'option choices définie. Si radio_admin est mis à True, Django utilisera des boutons radios à la place.

À ne pas utiliser pour les champs autres que ForeignKey ou ayant l'option choices définie.

unique

S'il est mis à True, le champ devra être unique sur toute la table.

Ce contrôle est effectué au niveau base de données, ainsi qu'au niveau des formulaires d'administration de Django.

unique_for_date

Donnez-lui comme valeur le nom d'un DateField ou d'un DateTimeField pour demander que ce champ soit unique en fonction de la valeur du champ de date.

Par exemple, si vous avez un champ titre qui possède unique_for_date="pub_date", alors Django n'autorisera pas la saisie de deux enregistrements avec le même titre et pub_date.

Ce contrôle est effectué au niveau des formulaires d'administration de Django, mais pas au niveau de la base de données.

unique_for_month

Comme unique_for_date, mais la contrainte d'unicité du champ se fait en fonction du mois.

unique_for_year

Comme unique_for_date et unique_for_month.

validator_list

Une liste de validateurs supplémentaires à appliquer sur le champ. Chacuns doivent être appelables (callable) en prenant les paramètres field_data, all_data et déclenchant django.core.validators.ValidationError en cas d'erreurs. (Lisez la documentation des validateurs.)

Django fournit quelques validateurs. Ils se trouvent dans django.core.validators.

Noms de champs explicites

Chaque type de champ, excepté ForeignKey, ManyToManyField et OneToOneField, prend un argument facultatif en première position -- un nom explicite. Si le nom explicite n'est pas donné, Django le créera automatiquement en utilisant le nom de l'attribut du champ, en convertissant les underscores en espaces.

Dans cet exemple, le nom explicite est "Prénom de la personne":

prenom = models.CharField("Prénom de la personne", maxlength=30)

Dans cet exemple, le nom explicite est "prenom":

prenom = models.CharField(maxlength=30)

ForeignKey, ManyToManyField et OneToOneField requièrent que le premier argument soit une classe de modèle, donc il faut utiliser l'argument mot-clé verbose_name:

sondage = models.ForeignKey(Sondage, verbose_name="le sondage associé")
sites = models.ManyToManyField(Site, verbose_name="liste de sites")
lieu = models.OneToOneField(Lieu, verbose_name="lieu associé")

Nous convenons de ne pas mettre de majuscule à la première lettre du verbose_name. Django mettra automatiquement la majuscule à la première lettre lorsque ça sera nécessaire.

Les relations

C'est clair, la puissance des bases de données relationnelles repose sur les relations entre les tables. Django offre la possibilité de définir les trois types de relations les plus courantes entre des tables de données: many-to-one (1..n), many-to-many (n..n) and one-to-one (1..1).

Les relations many-to-one

Pour définir une relation « many-to-one », utilisez ForeignKey. Vous l'utilisez simplement comme n'importe quel autre type Field: en l'incluant comme un attribut de classe du modèle.

ForeignKey requiert un argument en première position: La classe à laquelle le modèle est reliée.

Par exemple, si un modèle Voiture a un Constructeur -- à savoir qu'un Constructeur fabrique plusieurs voitures mais chaque Voiture n'a qu'un seul Constructeur -- utilisez les définitions suivantes:

class Constructeur(models.Model):
    # ...

class Voiture(models.Model):
    constructeur = models.ForeignKey(Constructeur)
    # ...

Pour créer une relation récursive -- un objet qui a une relation "many-to-one" avec lui-même -- utilisez models.ForeignKey('self').

Si vous avez besoin de créer une relation sur un modèle qui n'a pas encore été défini, vous pouvez utiliser le nom du modèle, plutôt que l'objet du modèle lui-même:

class Voiture(models.Model):
    constructeur = models.ForeignKey('Constructeur')
    # ...

class Constructeur(models.Model):
    # ...

Notez, cependant, que cette fonctionnalité d'utiliser des chaînes de caractères pour définir des noms de modèle dans ForeignKey est assez récente, et peut buguer un peu dans certains cas.

Derrière tout ça, Django concatène "_id" au nom du champ pour créer son nom de colonne de base de données. Dans l'exemple ci-dessus, la table de base de données pour le modèle Voiture aura une colonne constructeur_id. (Vous pouvez le changer explicitement en spécifiant db_column; voir db_column plus bas.) Cependant, votre code ne devrait jamais avoir à traiter avec le nom de colonne de la base de données, sauf si vous écrivez du code SQL perso. Vous traiterez toujours avec les noms de champ de votre objet de modèle.

Il est suggéré, mais non indispensable, que le nom d'un champ ForeignKey (constructeur dans l'exemple ci-dessus) soit le nom du modèle, en minuscules. Vous pouvez, bien-sûr, appeler le champ de la manière que vous voulez. Par exemple:

class Voiture(models.Model):
    societe_qui_la_fabrique = models.ForeignKey(Constructeur)
    # ...

Consultez l'exemple de modèle utilisant une relation Many-to-one pour un exemple complet.

Les champs ForeignKey prennent un certain nombre d'arguments supplémentaires pour définir comment devraient fonctionner les relations. Tous sont facultatifs:

Argument Description
edit_inline S'il n'est pas mis à False, l'objet est édité "en ligne" à l'intérieur de la page de l'objet associé, de manière imbriquée. Cela signifie que l'objet n'aura pas sa propre interface d'admin. Utilisez soit models.TABULAR, soit models.STACKED, qui, respectivement, désignent que les objets inbriqués sont affiché comme un tableau ou comme une "pile" de définitions de champs.
limit_choices_to

Un dictionnaire d'arguments de recherche et de valeurs (voir le document de référence de l'API de base de données) qui limite les choix disponible dans l'interface d'admin pour cet objet. Utilisez-le avec models.LazyDate pour limiter les choix des objets selon la date. Par exemple:

limit_choices_to = {'pub_date__lte': models.LazyDate()}

autorise seulement le choix des objets liés avec un pub_date antérieure à la date et heure actuelle pour être choisi.

À la place d'un dictionnaire, ça peut aussi être un objet Q (un objet avec une méthode get_sql()) pour des requêtes plus complexe.

Non compatible avec edit_inline.

max_num_in_admin

Pour les objets édités "en ligne", il s'agit du nombre maximum d'objets liés à afficher dans l'interface d'admin. Ainsi, si une pizza ne peut avoir que 10 ingrédients, max_num_in_admin=10 s'assurera qu'un utilisateur n'entre jamais plus de 10 ingrédients à la fois.

Notez que ça ne vérifiera pas si 10 ingrédients ont déjà été crées. Cette option ne contrôle que l'interface d'admin; il ne s'occupe pas du niveau API Python ni du niveau base de données.

min_num_in_admin Le nombre minimum d'objets liés affichés dans l'interface d'admin. Normalement, au stade de la création, les objets "en ligne" sont montrés au nombre de num_in_admin, et au stade de l'édition, des objects vide sont montrés au nombre de num_extra_on_change en plus de tous les objets liés pré-existants. Cependant, il n'y aura jamais d'objets liés affichés à un nombre inférieur à min_num_in_admin.
num_extra_on_change Le nombre de champs vides d'objets liés supplémentaires, montrés au stade de modification.
num_in_admin Le nombre par défaut d'objets "en ligne" à afficher sur la page de l'objet au stade de l'ajout.
raw_id_admin

Affiche seulement un champ pour saisir un nombre entier à la place d'un menu déroulant. C'est utile lorsqu'il est lié à un type d'objet qui aura trop d'enregistrements pour faire une boîte de sélection pratique.

Non utilisé avec edit_inline.

related_name Le nom à utiliser pour la relation depuis l'objet lié vers l'objet courant. Regardez la documentation sur les objets liés pour une explication complète et des exemples.
to_field Le champs de l'objet lié sur lequel porte la relation. Par défaut, Django utilise la clé primaire de l'objet lié.

Les relations many-to-many

Pour définir une relation many-to-many, utilisez la classe ManyToManyField. Vous n'avez qu'à l'utiliser comme n'importe quelle autre classe de type Field: en l'incluant comme un attribut de classe dans votre modèle.

ManyToManyField requiert un argument obligatoire: la classe vers laquelle le modèle est lié.

Par exemple, si une Pizza a de multiples objets Ingredient -- c'est-à-dire qu'un Ingredient peut être sur plusieurs pizzas et que chaque Pizza a plusieurs ingrédients -- voici comment vous représenteriez cela:

class Ingredient(models.Model):
    # ...

class Pizza(models.Model):
    # ...
    ingredients = models.ManyToManyField(Ingredient)

Comme avec la classe ForeignKey, une relation sur soi-même peut être définie en utilisant la chaîne de caractères 'self' à la place du nom du modèle, et vous pouvez référencer des modèles non encore définis en utilisant une chaîne de caractères contenant le nom du modèle.

Il est suggéré, mais non requis, que le nom d'un champ ManyToManyField (ingredients dans l'exemple ci-dessus) soit un pluriel décrivant l'ensemble des objets du modèle lié.

Derrière tout ça, Django crée une table de jointure intermédiaire pour représenter la relation many-to-many.

La définition de ManyToManyField dans l'un ou l'autre modèle n'a pas d'importance, mais vous devez le faire dans un seul des modèles -- pas dans les deux.

Généralement, les instances de ManyToManyField devraient être définies dans l'objet qui sera édité dans l'interface d'admin, si vous utilisez celle de Django. Dans l'exemple précédent, ingredients est dans Pizza (plutôt qu'avoir un champ ManyToManyField pizzas dans Ingredient) parce qu'il est plus naturel de penser à une pizza ayant des ingrédients que à un ingrédient présent dans plusieurs pizzas. Avec la manière dont c'est défini dans l'exemple, le formulaire d'administration de Pizza proposerait aux utilisateurs de sélectionner les ingrédients.

Regardez L'exemple de relation many-to-many entre modèles pour un exemple complet.

Les objets ManyToManyField prennent un certain nombre d'arguments supplémentaires pour définir la façon dont la relation devrait fonctionner. Tous sont facultatifs:

Argument Description
related_name Lisez la description dans la section ForeignKey plus haut.
filter_interface Utilise une interface de filtrage Javascript discrète et astucieuse au lieu d'un <select multiple> à l'utilité discutable, dans le formulaire d'administration de cet objet. La valeur devrait être models.HORIZONTAL ou models.VERTICAL (c'est à dire que l'interface devrait être empilée horizontalement ou verticalement).
limit_choices_to Lisez la description dans la section ForeignKey plus haut.
symmetrical

Uniquement employé dans la définition de champs ManyToManyFields sur eux-mêmes. Considérez le modèle suivant:

class Personne(models.Model):
amis = models.ManyToManyField("self")

Lorsque Django traite ce modèle, il reconnait avoir affaire à un ManyToManyField sur lui-même, et par conséquent, il n'ajoute pas d'attribut personne_set à la classe Personne. À la place, le ManyToManyField garantit d'être symétrique -- c'est-à-dire que si je suis ton ami, donc tu es mon ami.

Si vous ne voulez pas de symétrie dans vos relations ManyToMany avec 'self', définissez symmetrical à False. Cela forcera Django à ajouter un descripteur pour la relation inverse, permettant aux relations ManyToMany d'être asymétriques.

Les relations one-to-one

La sémantique des relations one-to-one est en cours de changement, nous ne vous recommandons donc pas de les utiliser. Si cela ne vous fait pas partir en courant, jetez un œil à ceci.

Pour définir une relation one-to-one, utilisez la classe OneToOneField. Vous n'avez qu'à l'employer comme n'importe quelle autre classe de type Field: en l'incluant comme attribut de classe dans votre modèle.

Il est des plus utiles sur la clé primaire d'un objet quand celui-ci "étend" un autre objet d'une certaine façon.

OneToOneField requiert un argument obligatoire: La classe vers laquelle le modèle est lié.

Par exemple, si vous êtes en train de construire une base de données de "lieux", vous définirez des données basiques tels qu'une adresse, un numéro de téléphone, etc. dans la base de données. Puis, si vous voulez construire une base de données de restaurants étendant la définition d'un lieu, plutôt que de vous répéter et de repliquer ces champs dans le modèle Restaurant, vous pourrez relier Restaurant à Lieu grâce à OneToOneField (parce qu'un restaurant "est-un" lieu).

Comme avec ForeignKey, une relation vers soi-même peut être définie en utilisant la chaîne de caractères "self" à la place du nom de modèle ; les références vers des modèles non encore définis peuvent être faites en utilisant une chaîne de caractères contenant le nom du modèle.

Ce OneToOneField remplacera en fait le champ de clé primaire id (puisque les relations one-to-one partagent la même clé primaire), et sera affiché comme un champ en lecture seule lorsque vous éditerez un objet dans l'interface d'admin:

Regardez l'exemple de relation one-to-one entre modèles pour un exemple complet.

Les options Meta

Définissez des métadonnées pour votre modèle en utilisant une classe interne Meta, comme ceci:

class Foo(models.Model):
    bar = models.CharField(maxlength=30)

    class Meta:
        # ...

Les métadonnées de modèle sont « tout ce qui n'est pas un champ », telles que les options de tri, etc.

Voici une liste de toutes les options Meta possibles. Aucune option n'est obligatoire. Ajouter la définition class Meta dans un modèle est tout à fait optionnel.

db_table

Le nom de la table de base de données à utiliser pour le modèle:

db_table = 'album_de_musique'

Si non défini, Django utilisera app_label + '_' + model_class_name. Voir « Les noms de table » plus bas pour plus de détails.

Si le nom de votre table de base de données est un mot réservé SQL, ou contient des caractères non permis dans les noms de variable Python -- notamment, le tiret -- cette option est faite pour vous. Django s'occupe ensuite de placer les noms de table et de colonne entre quotes automatiquement.

get_latest_by

Le nom d'un DateField ou DateTimeField dans le modèle. Cela spécifie le champ par défaut à utiliser dans la méthode latest() de votre modèle Manager.

Exemple:

get_latest_by = "date_commande"

Regardez les docs sur latest() pour plus de détails.

order_with_respect_to

Marque cet objet comme « triable » respectivement au champ donné. Ceci est presque toujours utilisé avec des objets liés pour permettre de les trier respectivement à un objet parent. Par exemple, si une Reponse est liée à un objet Question, et qu'une question possède plus d'une réponse, et que l'ordre des réponses importe, vous ferez ceci:

class Reponse(models.Model):
    question = models.ForeignKey(Question)
    # ...

    class Meta:
        order_with_respect_to = 'question'

ordering

Le tri par défaut pour l'objet, utilisé pour obtenir des listes d'objets:

ordering = ['-date_commande']

Il s'agit d'un tuple ou d'une liste de chaînes de caractères. Chaque chaîne est un nom de champ avec un préfixe facultatif "-", qui indique un ordre décroissant. Les champs sans un "-" devant seront triés dans l'ordre croissant. Utilisez la chaîne "?" pour mélanger aléatoirement.

Par exemple, pour trier selon un champ date_publication de manière croissante, utilisez ceci:

ordering = ['date_publication']

Pour trier selon date_publication de manière décroissante, utilisez ceci:

ordering = ['-date_publication']

Pour trier selon date_publication de manière décroissante, puis selon auteur de manière croissante, utilisez ceci:

ordering = ['-date_publication', 'auteur']

Regardez Spécifier un ordre de tri pour plus d'exemples.

Notez que, sans regarder combien de champs sont dans ordering, le site d'administration utilise seulement le premier champ.

permissions

Ce sont des permissions supplémentaires pour entrer dans la table de permission lors de la création de cet objet. Les permissions d'ajout, suppression et modification sont automatiquement créées pour chaque objet dont admin est défini. Cet exemple spécifie une permission supplémentaire, peut_livrer_pizzas:

permissions = (("peut_livrer_pizzas", "Peut livrer des pizzas"),)

Il s'agit d'une liste ou d'un tuple formé de paire (tuples de 2 éléments) dans le format (code_de_la_permission, nom_intuitif_de_la_permission).

unique_together

Définit les noms de champ qui, pris ensemble, doivent être uniques:

unique_together = (("livreur", "restaurant"),)

Il s'agit d'une liste de listes des champs qui doivent être uniques lorsqu'ils sont considérés ensemble. C'est utilisé dans l'administration de Django et est renforcé au niveau de la base de données (c'est-à-dire que l'instruction UNIQUE appropriée est incluse dans la clause CREATE TABLE).

verbose_name

Un nom intuitif pour l'objet, au singulier:

verbose_name = "pizza"

Si non défini, Django utilisera une version décomposée du nom de la classe: MiseAJour devient mise a jour.

verbose_name_plural

Le nom au pluriel de l'objet:

verbose_name_plural = "animaux"

Si non défini, Django utilisera verbose_name + "s".

Les noms de table

Pour vous faire gagner du temps, Django détermine le nom de la table de base de données à partir du nom de votre classe de modèle et de l'application à laquelle elle appartient. Un nom d'une table correspondant à un modèle est construit en joignant le libellé de l'application auquel appartient le modèle -- le nom que vous employez dans manage.py startapp -- avec le nom de la classe du modèle, séparés par un underscore entre les deux.

Par exemple, si vous avez une application librairie (comme créée par manage.py startapp librairie), un modèle défini comme class Livre aura une table de base de données nommée librairie_livre.

Pour personnaliser le nom de la table, utilisez le paramètre db_table dans la classe Meta.

Les champs de clé primaire automatiques

Par défaut, Django attribue à chaque modèle le champ suivant:

id = models.AutoField(primary_key=True)

Il s'agit d'une clé primaire qui s'incrémente automatiquement.

Si vous désirez spécifier une clé primaire personnalisée, indiquez simplement primary_key=True à l'un de vos champs. Si Django voit que vous avez defini explicitement primary_key, il n'ajoutera pas la colonne id automatique.

Chaque modèle ne doit contenir qu'un seul champ défini avec primary_key=True.

Les options d'administration

Si vous voulez que votre modèle soit visible dans le site d'administration de Django, donnez à votre modèle une classe interne "Admin", comme ceci:

class Personne(models.Model):
    prenom = models.CharField(maxlength=30)
    nom = models.CharField(maxlength=30)

    class Admin:
        # Les options d'administration vont ici
        pass

La classe Admin indique à Django comment afficher le modèle dans le site d'admin.

Voici une liste de toutes les options possibles de la classe Admin. Aucune de ces options n'est obligatoire. Pour utiliser une interface d'admin sans définir d'option, utilisez l'instruction pass, comme ceci:

class Admin:
    pass

L'ajout de class Admin dans un modèle est tout à fait optionnel.

date_hierarchy

Affectez à date_hierarchy le nom d'un DateField ou DateTimeField de votre modèle, et la page de listage pour modification inclura un menu de navigation calendaire en fonction de ce champ.

Exemple:

date_hierarchy = 'date_publication'

fields

Définissez fields pour contrôler la disposition graphique des pages d'ajout et de modification de l'interface d'admin.

fields est une liste de paires (tuple de 2 éléments), dans lequel chaque paire représente un <fieldset> dans la page du formulaire. (Un <fieldset> est une "section" du formulaire.)

Les paires sont définies par le format (nom, options_de_champ), où nom est une chaîne de caractères représentant le titre de la section "fieldset" et options_de_champ est un dictionnaire d'informations au sujet de la section "fieldset", dont une liste des champs à afficher dans cette section.

Un exemple concret, extrait du modèle django.contrib.flatpages.FlatPage (ndt: exemple soumis à traduction):

class Admin:
    fields = (
        (None, {
            'fields': ('url', 'titre', 'contenu', 'sites')
        }),
        ('Options avancées', {
            'classes': 'collapse',
            'fields' : ('permettre_commentaires', 'inscription_requise', 'nom_du_template')
        }),
    )

Cela donne comme résultat une page d'administration qui ressemble à ceci:

/site_media/images/flatfiles_admin.png

Si fields n'est pas défini, Django affichera par défaut chaque champ qui n'est pas un AutoField et qui a editable=True, dans une section unique et dans le même ordre que celui dans lequel les champs ont été déclarés dans le modèle.

Le dictionnaire field_options peut avoir les clés suivantes:

fields

Un tuple de noms de champ à afficher dans la section. Cette clé est nécessaire.

Exemple:

{
'fields': ('prenom', 'nom', 'adresse', 'ville', 'pays'),
}

Pour afficher plusieurs champs sur la même ligne, enveloppez ces champs dans un même tuple. Dans cet exemple, les champs prenom et nom s'afficheront sur la même ligne:

{
'fields': (('prenom', 'nom'), 'adresse', 'ville', 'pays'),
}

classes

Une chaîne de caractères contenant des classes CSS supplémentaires à appliquer au fieldset.

Exemple:

{
'classes': 'wide',
}

Appliquez plusieurs classes en les séparant par des espaces. Exemple:

{
'classes': 'wide extrapretty',
}

Deux classes utiles sont définies dans la feuille de style par défaut du site d'admin : collapse et wide. Les sections avec le style collapse seront initialement repliées dans la page d'admin et remplacée par une petit lien « cliquez pour déplier». Les sections avec le style wide auront un espacement horizontal supplémentaire.

description

Une chaîne de caractères de texte supplémentaire facultatif à afficher au dessus de chaque section, sous l'en-tête de la section. Cette chaîne est utilisée telle quelle, donc vous pouvez utilisez des balises HTML et devez de ce fait, prendre garde à échapper vous-même les caractères spéciaux du HTML (tels que l'esperluette -- &).

js

Une liste de chaînes de caractères représentant des URLs de fichiers JavaScript pour les lier aux pages d'administration via des balises <script src="">. Cela peut être utile pour formater ou vérifier un type donné dans la page d'administration en JavaScript ou pour fournir des raccourcis permettant de choisir des valeurs standards pour certains champs.

list_display

Définissez list_display pour contrôler quels champs seront affichés dans la page de listage pour modification dans le site d'administration.

Exemple:

list_display = ('prenom', 'nom')

Si vous ne définissez pas list_display, le site d'admin affichera une colonne unique qui contiendra la représentation __str__() de chaque objet.

Quelques cas spéciaux à noter au sujet de list_display:

  • Si le champ est une clé étrangère ForeignKey, Django affichera le __str__() de l'objet lié.

  • Les champs ManyToManyField ne sont pas supportés, parce que cela obligerait l'exécution d'une requête SQL séparée pour chaque enregistrement de la table.

  • Si le champ est un BooleanField, Django affichera une jolie icone "on" ou "off" plutôt que True ou False.

  • Si la chaîne donnée est une méthode du modèle, Django l'appellera et affichera le résultat. Cette méthode devrait avoir un attribut de fonction short_description, pour une utilisation comme en-tête de champ.

    Voici un exemple complet de modèle:

    class Personne(models.Model):
        nom = models.CharField(maxlength=50)
        date_naissance = models.DateField()
    
        class Admin:
            list_display = ('nom', 'calculer_decennie')
    
        def calculer_decennie(self):
            return self.date_naissance.strftime('%Y')[:3] + "0's"
        calculer_decennie.short_description = 'Décennie de naissance'
    

list_filter

Définissez list_filter pour activer des filtres dans la barre à droite de l'écran, dans la page de listage pour modification du site d'admin. Ce devrait être une liste de noms de champs, et chaque champ spécifié devrait être un BooleanField, DateField, DateTimeField ou ForeignKey.

Cet exemple, extrait du modèle django.contrib.auth.models.User, montre comment list_display et list_filter fonctionnent toutes les deux:

class Admin:
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    list_filter = ('is_staff', 'is_superuser')

Le code ci-dessus donne comme résultat une page de listage pour modification qui ressemble à ceci:

/site_media/images/users_changelist.png

(Cet exemple contient aussi une définition de search_fields. Voir plus bas.)

list_per_page

Définissez list_per_page pour contrôler combien d'items apparaissent dans chaque écran paginé d'une page de listage pour modification. Par défaut, ce nombre est défini à 100.

list_select_related

Définissez list_select_related pour indiquer à Django d'utiliser select_related() pour retrouver la liste d'objets sur la page de listage pour modification. Cela peut vous épargner un paquet de requêtes SQL.

La valeur devrait être soit True, soit False. False par défaut.

Notez que Django utilisera select_related(), sans tenir compte de ce paramètre, si un des champs contenus dans list_display est une clé étrangère ForeignKey.

Pour en savoir plus sur select_related(), regardez les docs à propos de select_related().

ordering

Définissez ordering pour spécifier comment les objets de la page de listage pour modification devraient être triés. Il devrait s'agir d'une liste ou tuple dans le même format que le paramètre ordering du modèle.

Si non défini, Django utilisera le tri par défaut du modèle.

save_as

Définissez save_as pour rendre disponible la fonctionnalité « enregistrer sous » dans les formulaires d'édition du site d'administration.

Normalement, les objets ont trois options de sauvegarde: « Sauver », « Sauver et continuer » et « Sauver et ajouter un nouveau ». Si save_as est à True, « Sauver et ajouter un nouveau » sera remplacé par un bouton « Enregistrer sous ».

« Enregistrer sour » signifie que l'objet sera sauvegardé comme un nouvel objet (avec une nouvel identifiant), au lieu de remplacer l'ancien.

Par défaut, save_as est à False.

save_on_top

Définissez save_on_top pour ajouter les boutons de sauvegarde en haut des formulaires d'édition.

Normalement, les boutons de sauvegarde apparaissent seulement en bas de formulaires. Si vous définissez save_on_top, les boutons apparaitront à la fois en haut et en bas.

Par défaut, save_on_top est à False.

search_fields

Définissez search_fields pour rendre disponible une boîte de recherche sur la page de listage pour modification. Cela devrait être défini à l'aide d'une liste de noms de champ dans lesquels s'effectuera la recherche lorsque quelqu'un soumet une recherche dans cette boîte de texte.

Ces champs devraient être un type de champ textuel, tel que CharField ou TextField.

Quand quelqu'un fait une recherche dans la boîte de recherche du site d'administration, Django découpe le texte saisi en mots et retourne tous les objets qui contiennent chacun de ces mots, de manière insensible à la casse, où chaque mot doit apparaître dans au moins un champ contenu dans search_fields. Par exemple, si search_fields est défini à ['prenom', 'nom'] et qu'un utilisateur recherche un john lennon, Django fera l'équivalent de cette clause SQL WHERE:

WHERE (prenom ILIKE '%john%' OR nom ILIKE '%john%')
AND (prenom ILIKE '%lennon%' OR nom ILIKE '%lennon%')

Les gestionnaires

Un Gestionnaire est une interface à travers laquelle les opérations de requête de base de données sont fournies aux modèles Django. Au moins un Gestionnaire existe pour tout modèle d'une application Django.

La façon dont les classes des Gestionnaires fonctionne est documentée dans la section Retrouver des objets de la doc sur l'API d'accès à la base de données, mais cette section touche spécifiquement aux options de modèle qui personnalisent le comportement d'un Gestionnaire.

Les noms de gestionnaire

Par défaut, Django ajoute un Gestionnaire baptisé objects à toute classe de modèle Django. Cependant, si vous voulez utiliser objects comme un nom de champ, ou si vous voulez utiliser un autre nom que objects pour le Gestionnaire, vous pouvez le renommer sur une base "par modèle". Pour renommer le Gestionnaire d'une classe donnée, définissez un attribut de classe de type models.Manager() dans ce modèle. Par exemple:

from django.db import models

class Personne(models.Model):
    #...
    gens = models.Manager()

En utilisant cet exemple de modèle, Personne.gens générera une exception AttributeError, mais Personne.gens.all() fournira une liste de tous les objets Personne.

Personnalisation des gestionnaires

Vous pouvez utiliser un Gestionnaire personnalisé dans un modèle particulier en étendant la classe de base et en instanciant votre propre Gestionnaire dans votre modèle.

Il y a deux raisons motivant la personnalisation d'un Gestionnaire: ajouter des méthodes de Gestionnaire supplémentaires, et/ou modifier le QuerySet initial que retourne le gestionnaire Manager.

Ajout de méthodes de gestionnaire supplémentaires

Ajouter des méthodes de Gestionnaire supplémentaires est le meilleur moyen pour ajouter une fonctionnalité au niveau de la table de base de données de vos modèles. (Pour une fonctionnalité au niveau enregistrement -- c'est-à-dire, des fonctions qui agissent sur une seule instance d'un objet de modèle -- utilisez les méthodes de modèles et non les méthodes de Gestionnaire personnalisées.)

Une méthode de Gestionnaire personnalisée peut retourner ce que vous voulez. Elle n'est pas tenu de retourner un QuerySet.

Par exemple, ce Gestionnaire personnalisé propose une méthode avec_effectifs(), qui retourne une liste de tous les objets SondageDOpinion, chacun avec un attribut supplémentaire nb_reponses qui contient le résultat d'une requête d'aggrégation:

class GestionnaireSondage(models.Manager):
    def avec_effectifs(self):
        from django.db import connection
        curseur = connection.cursor()
        curseur.execute("""
            SELECT s.id, s.question, s.date_sondage, COUNT(*)
            FROM sondages_sondagedopinion s, sondages_reponse r
            WHERE s.id = r.sondage_id
            GROUP BY 1, 2, 3
            ORDER BY 3 DESC""")
        liste_resultats = []
        for enreg in curseur.fetchall():
            s = self.model(id=enreg[0], question=enreg[1], date_sondage=enreg[2])
            s.nb_reponses = enreg[3]
            liste_resultats.append(s)
        return liste_resultats

class SondageDOpinion(models.Model):
    question = models.CharField(maxlength=200)
    date_sondage = models.DateField()
    objects = GestionnaireSondage()

class Reponse(models.Model):
    sondage = models.ForeignKey(Sondage)
    nom_personne = models.CharField(maxlength=50)
    reponse = models.TextField()

Avec cet exemple, vous utiliseriez SondageDOpinion.objects.avec_effectifs() pour retourner cette liste d'objets OpinionPoll avec l'attribut nb_reponses.

Une autre chose à noter à propos de cet exemple, c'est que les méthodes de Gestionnaire peuvent accéder à self.model pour atteindre la classe de modèle à laquelle ces méthodes sont rattachées.

Modifier les QuerySets de gestionnaire initiaux

Un QuerySet standard du gestionnaire Manager retourne tout les objets du système. Par exemple, en utilisant ce modèle:

class Livre(models.Model):
    titre = models.CharField(maxlength=100)
    auteur = models.CharField(maxlength=50)

...l'instruction Livre.objects.all() retournera tous les livres de la base de données.

Vous pouvez modifier le comportement d'un QuerySet standard en surchargeant la méthode Manager.get_query_set(). get_query_set() devrait retourner un QuerySet avec les propriétés dont vous avez besoin.

Par exemple, le modèle suivant possède deux Gestionnaires -- un qui retourne tous les objets, et un qui retourne seulement les livres de Roald Dahl:

# En premier, definissons la sous-classe de Manager.
class GestionnaireLivresRoaldDahl(models.Manager):
    def get_query_set(self):
        return super(GestionnaireLivresRoaldDahl, self).get_query_set().filter(auteur='Roald Dahl')

# Puis accrochons-le explicitement dans le modèle Livre.
class Livre(models.Model):
    titre = models.CharField(maxlength=100)
    auteur = models.CharField(maxlength=50)

    objects = models.Manager() # The default manager.
    dahl_objects = GestionnaireLivresRoaldDahl() # Le gestionnaire spécifiques aux oeuvres de Roald Dahl.

Avec ce modèle, Livre.objects.all() retournera tous les livres de la base de données, mais Livre.dahl_objects.all() retournera seulement ceux écrits par Roald Dahl.

Bien-sûr, comme get_query_set() retourne un objet QuerySet, vous pouvez utiliser filter(), exclude() et toutes les autres méthodes de QuerySet sur cela. Par conséquent, ces instructions sont toutes correctes:

Livre.dahl_objects.all()
Livre.dahl_objects.filter(titre='Matilda')
Livre.dahl_objects.count()

Cet exemple indique également une autre technique intéressante: l'utilisation de plusieurs gestionnaires sur un même modèle. Vous pouvez rattacher autant d'instances de Gestionnaire que vous voulez à un modèle. Cela est une manière facile de définir des "filtres" courants à vos modèles.

Par exemple:

class GestionnaireHomme(models.Manager):
    def get_query_set(self):
        return super(GestionnaireHomme, self).get_query_set().filter(sexe='H')

class GestionnaireFemme(models.Manager):
    def get_query_set(self):
        return super(GestionnaireFemme, self).get_query_set().filter(sexe='F')

class Personne(models.Model):
    prenom = models.CharField(maxlength=50)
    nom = models.CharField(maxlength=50)
    sexe = models.CharField(maxlength=1, choices=(('H', 'Homme'), ('F', 'Femme')))
    gens = models.Manager()
    hommes = GestionnaireHomme()
    femmes = GestionnaireFemme()

Ce exemple vous permet d'effectuer les requêtes Personne.hommes.all(), Personne.femmes.all(), et Personne.gens.all() délivrant des résultats prévisibles.

Si vous utilisez des objets de Gestionnaire personnalisés, prenez note que le premier Gestionnaire que Django rencontre (dans l'ordre où ils sont définis dans le modèle) possède un statut spécial. Django interprète le premier Gestionnaire défini dans une classe comme le Gestionnaire "par défaut". Certaines opérations -- telles que le site d'administration de Django -- utilisent le Gestionnaire par défaut pour obtenir des listes d'objets, donc il est générallement préférable que le premier Gestionnaire soit relativement non-filtré. Dans l'exemple précédent, le gestionnaire gens est défini en premier -- donc il est le Gestionnaire par défaut.

Les méthodes de modèle

Définissez des méthodes personnalisées dans un modèle pour ajouter une fonctionnalité personnalisée au niveau enregistrement de base de données dans vos objets. Alors que les méthodes de Gestionnaire sont sensées faire des choses au niveau table de base de données, les méthodes de modèle devraient agir sur une instance particulière du modèle.

Il s'agit d'une technique efficace pour garder les affaires de logique dans un seul et même endroit -- le modèle.

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

class Personne(models.Model):
    prenom = models.CharField(maxlength=50)
    nom = models.CharField(maxlength=50)
    date_naissance = models.DateField()
    adresse = models.CharField(maxlength=100)
    ville = models.CharField(maxlength=50)
    etat = models.USStateField() # Oui, c'est un exemple tres americano-centrique...

    def statut_de_babyboomer(self):
        "Retourne le statut de babyboomer de la personne."
        import datetime
        if datetime.date(1945, 8, 1) <= self.date_naissance <= datetime.date(1964, 12, 31):
            return "Baby-boomer"
        if self.date_naissance < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        return "Post-boomer"

    def est_du_midwest(self):
        "Retourne True si cette personne est du Midwest."
        return self.etat in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')

    def _get_nom_complet(self):
        "Retourne le nom complet de la personne."
        return '%s %s' % (self.prenom, self.nom)
    nom_complet = property(_get_nom_complet)

La dernière méthode dans cet exemple est une propriété. Lisez plus d'infos sur les propriétés.

Quelques méthodes d'objet ont une signification spéciale:

__str__

__str__() est une "méthode magique" de Python qui décrit ce qui devrait être retourné si vous appelez str() sur l'objet. Django utilise str(obj) dans bon nombre d'endroits, notamment pour les valeurs affichées pour représenter un objet dans le site d'administration de Django et pour la valeur insérée dans un template qui affiche un objet. Ainsi, vous devriez toujours retourner une chaîne de caractères jolie et lisible pour la méthode __str__ de l'objet. Même si ce n'est pas obligatoire, c'est fortement recommandé.

Par exemple:

class Personne(models.Model):
    prenom = models.CharField(maxlength=50)
    nom = models.CharField(maxlength=50)

    def __str__(self):
        return '%s %s' % (self.prenom, self.nom)

get_absolute_url

Définissez une méthode get_absolute_url() pour indiquer à Django comme calculer l'URL d'un objet. Par exemple:

def get_absolute_url(self):
    return "/gens/%i/" % self.id

Django utilise cela dans son interface d'admin. Si un objet définit get_absolute_url(), la page d'édition d'objet aura un lien "Visualiser sur le site" qui sautera directement à la vue publique de l'objet, selon get_absolute_url().

Divers autres modules de Django, tels que le framework de "syndication-feed", utilisent également get_absolute_url() ce qui est une bonne nouvelle pour les gens qui ont défini la méthode.

Il est d'une meilleure pratique d'utiliser get_absolute_url() dans les templates, plutôt que des URLs d'objets codés en dur. Par exemple, ce code de template est mauvais:

<a href="/gens/{{ object.id }}/">{{ object.nom }}</a>

Mais ce code de template est bon:

<a href="{{ object.get_absolute_url }}">{{ object.nom }}</a>

(Oui, nous reconnaissons que get_absolute_url() produit une redondance des URLs vers les modèles, ce qui viole le principe DRY, parce que les URLs sont définis à la fois dans l'URLconf et dans le modèle. Ceci est un cas rare dans lequel nous violons intentionnellement ce principe pour le compte de l'intuitivité. Cela dit, nous sommes en train de travailler sur une manière encore plus propre de spécifier les URLs dans une mode plus DRY.)

Exécuter du SQL personnalisé

Soyez libre d'écrire vos propre instructions SQL dans les méthodes de modèle personnalisées et les méthodes de niveau module. L'objet django.db.connection représente la connexion courante à la base de données. Pour l'utiliser, appelez connection.cursor() pour obtenir un objet curseur. Puis, appelez cursor.execute(sql, [params]) pour exécuter du code SQL et cursor.fetchone() ou cursor.fetchall() pour retourner des lignes de résultats. Exemple:

def mon_propre_sql(self):
    from django.db import connection
    curseur = connection.cursor()
    curseur.execute("SELECT colonnes FROM ma_table WHERE condition = %s", [self.condition])
    enreg = curseur.fetchone()
    return enreg

connection et curseur utilisent simplement le standard DB-API de Python. Si vous n'êtes pas familiarisé avec le DB-API de Python, notez que les instructions SQL dans cursor.execute() utilisent la syntaxe de formatage des chaînes, "%s", plutôt que l'ajout de paramètres directement dans le code SQL. Si vous utilisez cette technique, la bibliothèque de base de données sous-jacente ajoutera automatiquement des quotes et des échappements à vos paramètres, si nécessaire. (De plus, notez que Django attend la syntaxe "%s", et non la syntaxe "?", qui est utilisée par les bindings Python de SQLite. C'est pour le bien de l'uniformité et de la propreté.)

Un note finale: Si tout ce que vous désirez faire est une clause WHERE personnalisée, vous pouvez juste définir les arguments where, tables et params dans l'API standard de requêtes. Voir Autres options de requête.

Surcharger les méthodes de modèle par défaut

Comme expliqué dans la doc de l'API d'accès la base de données, chaque modèle obtient quelques méthodes automatiquement -- notemment, save() et delete(). Vous pouvez surcharger ces méthodes pour altérer leur comportement.

Un cas d'utilisation classique pour la surcharge de méthodes intégrées est si vous voulez que quelque chose se passe lorsque vous enregistrez un objet. Par exemple:

class Blog(models.Model):
    nom = models.CharField(maxlength=100)
    tags = models.TextField()

    def save(self):
        faire_quelque_chose()
        super(Blog, self).save() # Appel de la methode save() "reelle".
        faire_encore_quelque_chose()

Vous pouvez aussi empécher la sauvegarde:

class Blog(models.Model):
    nom = models.CharField(maxlength=100)
    tags = models.TextField()

    def save(self):
        if self.nom == "Le blog de Yoko Ono":
            return # Yoko n'aura jamais son propre blog!
        else:
            super(Blog, self).save() # Appel de la methode save() "reelle".

Les modèles à travers plusieurs fichiers

Il est parfaitement possible de relier un modèle à un second d'une autre application. Pour ce faire, importez juste le modèle lié en haut du fichier qui garde votre modèle. Puis, référencez-le simplement dans l'autre classe de modèle là où vous en avez besoin. Par exemple:

from monsite.geographie.models import CodePostal

class Restaurant(models.Model):
    # ...
    code_postal = models.ForeignKey(CodePostal)

Utiliser des modèles

Une fois que vos modèles sont créés, l'étape finale est d'indiquer à Django que vous allez utiliser ces modèles.

Faites cela en éditant votre fichier de configuration et en modifiant le paramètre INSTALLED_APPS pour ajouter le nom du module qui contient votre models.py.

Par exemple, si les modèles pour votre application logent dans le module monsite.monappli.models (la structure de paquetage qui est créée pour une application par le script manage.py startapp), INSTALLED_APPS devrait contenir, dans un coin:

INSTALLED_APPS = (
    #...
    'monsite.monappli',
    #...
)

Fournir des données SQL initiales

Django propose une astuce pour passer du code SQL arbitraire qui serait exécuté juste après les instructions CREATE TABLE. Utilisez cette astuce, par exemple, si vous voulez initialiser des enregistrements par défaut, ou créer des fonctions SQL, automatiquement.

L'astuce est simple: Django recherche juste un fichier nommé <nom_appli>/sql/<nom_modele>.sql, où <nom_appli> est le répertoire de votre application et <nom_modele> est le nom du modèle en minuscules.

Dans le modèle d'exemple Personne en haut de ce document, supposons qu'il loge dans une application nommée monappli, vous pourriez ajouter du code SQL arbitraire dans le fichier monappli/sql/personne.sql. Voici un exemple de ce que le fichier pourrait contenir:

INSERT INTO monappli_personne (prenom, nom) VALUES ('John', 'Lennon');
INSERT INTO monappli_personne (prenom, nom) VALUES ('Paul', 'McCartney');

Chaque fichier SQL, si défini, est tenu de contenir du code SQL valide. Les fichiers SQL sont transférés via un tube directement dans la base de données après que toutes les instructions de création de table des modèles aient été exécutées.

Les fichiers SQL sont lus par les commandes sqlinitialdata, sqlreset, sqlall et reset dans manage.py. Référez-vous à la documentation de manage.py pour plus d'informations.

Notez que si vous avez plusieurs fichiers de données SQL, l'ordre dans lequel ils sont exécutés n'est pas garanti. La seule chose dont vous pouvez être sûr, c'est que au moment où vos fichiers de données sont exécutés, toutes les tables de la base de données auront déjà été créées.

Données SQL spécifiques au système de gestion de base de données

Il y a aussi une astuce pour les données spécifiques au SGBD. Par exemple, vous pouvez avoir des fichiers de données initiales séparés pour PostgreSQL et MySQL. Pour chaque application, Django recherche un fichier nommé <nom_appli>/sql/<nom_modele>.<sgbd>.sql, où <nom_appli> est le répertoire de votre application, <nom_modele>``est le nom du modèle en minuscules et ``<sgbd> est la valeur du paramètre DATABASE_ENGINE dans votre fichier de configuration (par exemple, postgresql, mysql).

Les données SQL spécifiques au SGBD sont exécutées avant les données SQL non-spécifiques. Par exemple, si votre application contient les fichiers sql/personne.sql et sql/personne.postgresql.sql et que vous installez l'application sur PostgreSQL, Django exécutera le contenu de sql/personne.postgresql.sql en premier, puis celui de sql/personne.sql.