• 40 hours
  • Medium

Free online content available in this course.

Paperback available in this course

course.header.alt.is_certifying

You can get support and mentoring from a private teacher via videoconference on this course.

Got it!

Last updated on 10/11/19

L'administration

Log in or subscribe for free to enjoy all this course has to offer!

Sur un bon nombre de sites, l'interface d'administration est un élément capital à ne pas négliger lors du développement. C'est cette partie qui permet en effet de gérer les diverses informations disponibles : les articles d'un blog, les comptes utilisateurs, etc.
Un des gros points forts de Django est que celui-ci génère de façon automatique l'administration en fonction de vos modèles. Celle-ci est personnalisable à souhait en quelques lignes et est très puissante.

Nous verrons dans ce chapitre comment déployer l'administration et la personnaliser.

Mise en place de l'administration

Les modules django.contrib

L'administration Django est optionnelle : il est tout à fait possible de développer un site sans l'utiliser. Pour cette raison, elle est placée dans le module django.contrib, contenant un ensemble d'extensions fournies par Django, réutilisables dans n'importe quel projet. Ces modules sont bien pensés et vous permettent d'éviter de réinventer la roue à chaque fois.
Nous allons étudier ici le module django.contrib.admin  qui génère l'administration. Il existe toutefois bien d'autres modules, dont certains que nous aborderons par la suite :django.contrib.messages  (gestion de messages destinés aux visiteurs),django.contrib.auth  (système d'authentification et de gestion des utilisateurs), etc.

Accédons à cette administration !

Ce module est optionnel mais il est tellement utilisé que la configuration par défaut l'intègre désormais. Cependant, pour ceux qui auraient modifié la configuration, voici un petit rappel.

Import des modules

Tout d'abord, ayez dans votre liste INSTALLED_APPS  de votre settings.py  les applications suivantes, déjà présent au début de la liste par défaut :

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',

En plus de l'application admin, les quatres autres sont nécessaires pour le fonctionnement de l'administration. Ensuite, le module d'administration nécessite aussi l'import de middlewares, normalement inclus par défaut également :

'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',

Sauvegardez le fichier settings.py. Désormais, lors du lancement du serveur, le module contenant l'administration sera importé.

Mise à jour de la base de données

Pour fonctionner, il faut créer de nouvelles tables dans la base de données, qui serviront à enregistrer les actions des administrateurs, définir les droits de chacun, etc. Si vous ne l'avez pas déjà fait au moins une fois, il faut exécuter python manage.py migrate . Ensuite, il nous faut créer un compte super-utilisateur. Il sera au début le seul compte à pouvoir accéder à l'administration.

Pour ce faire, vous devez taper la commande suivante :

python manage.py createsuperuser

Insérez les informations utilisateur que Django vous demande (nom d'utilisateur, e-mail, mot de passe).

Intégration à notre projet : définissons-lui une adresse

Enfin, tout comme pour nos vues, il est nécessaire de dire au serveur « Quand j'appelle cette URL, redirige-moi vers l'administration. » En effet, pour l'instant nous avons bel et bien importé le module, mais nous ne pouvons pas encore y accéder.

Comme pour les vues, cela se fait à partir d'un urls.py. Ouvrez le fichiercrepes_bretonnes/urls.py. Par défaut, Django a déjà indiqué une ligne pour l'administration normalement. Votre fichier devrait ressembler à ceci :

"""crepes_bretonnes URL Configuration

[...]
"""
from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    # l'include vers blog/urls.py que l'on a mis dans les chapitres précédents
    path('blog/', include('blog.urls')),  
]

L'administration est donc disponible à l'adresse http://localhost:8000/admin/. Nous pouvons donc tester en lançant le serveur Django. Vous pouvez dès lors accéder à l'administration depuis l'URL définie (voir la figure suivante), il suffira juste de vous connecter avec le nom d'utilisateur et le mot de passe que vous avez spécifiés via la commande createsuperuser .

L'écran de connexion de l'administration
L'écran de connexion de l'administration

Première prise en main

Une fois que vous avez saisi vos identifiants de super-utilisateur, vous devez arriver sur une page semblable à la figure suivante.

Accueil de l'administration
Accueil de l'administration

C'est encore un peu vide, mais ne vous inquiétez pas, nous allons bientôt pouvoir manipuler nos modèlesArticle  et Categorie, rédigés dans le chapitre précédent.
Tout d'abord, faisons un petit tour des fonctionnalités disponibles. Sur cette page, vous avez la liste des modèles que vous pouvez gérer. Pour le moment, seul 2 modèles, Groupes et Utilisateurs sont disponibles, par défaut. Ce sont les modèles de l'application django.contrib.auth.
Chaque modèle possède ensuite une interface qui permet de réaliser les 4 opérations de base « CRUD » : Create, Read, Update, Delete (littéralement créer, lire, mettre à jour, supprimer).
Pour ce faire, allons dans l'administration des comptes sur notre site, en cliquant sur Utilisateurs. Pour le moment, vous n'avez logiquement qu'un compte dans la liste, le vôtre, ainsi que vous pouvez le voir sur la figure suivante.

Liste des utilisateurs
Liste des utilisateurs

C'est à partir d'ici que nous pouvons constater la puissance de cette administration : sans avoir écrit une seule ligne de code, il est possible de manipuler la liste des utilisateurs dans tous les sens : la filtrer selon certains paramètres, la trier avec certains champs, effectuer des actions sur certaines lignes, etc.

Pour essayer ces opérations, nous allons d'abord créer un deuxième compte utilisateur. Il suffit de cliquer sur le bouton Ajouter utilisateur, en haut à droite. Le premier formulaire vous demande de renseigner le nom d'utilisateur et le mot de passe. Nous pouvons déjà remarquer sur la figure suivante que les formulaires peuvent gérer des contraintes, et l'affichage d'erreurs.

Formulaire de création de comptes, après le validateur avec erreur
Formulaire de création de comptes, après le validateur avec erreur

Une fois cela validé, vous accédez directement à un formulaire plus complet, permettant de renseigner plus d'informations sur l'utilisateur qui vient d'être créé : ses informations personnelles, mais aussi ses droits sur le site.
Django fournit de base une gestion précise des droits, par groupe et par utilisateur, offrant souplesse et rapidité dans l'attribution des droits. Ainsi, ici nous pouvons voir qu'il est possible d'assigner un ou plusieurs groupes à l'utilisateur, et des permissions spécifiques. Ces groupes peuvent être créés dans l'administration des groupes que nous avons vu sur l'accueil au début.
Également, deux champs importants sontStatut équipe  et Statut super-utilisateur  : le premier permet de définir si l'utilisateur peut accéder au panel d'administration, et le second de donner « les pleins pouvoirs » à l'utilisateur (voir la figure suivante).

Exemple d'édition des permissions
Exemple d'édition des permissions

Une fois que vous avez fini de gérer l'utilisateur, vous êtes redirigés vers la liste de tout à l'heure, avec une ligne en plus. Désormais, vous pouvez tester le tri, et les filtres qui sont disponibles à la droite du tableau ! Nous verrons d'ailleurs plus tard comment définir les champs à afficher, quels filtres utiliser, etc.

En définitive, pour finir ce rapide tour des fonctionnalités, vous avez peut-être remarqué la présence d'un bouton Historique haut de chaque fiche utilisateur ou groupe. Ce bouton est très pratique, puisqu'il vous permet de suivre les modifications apportées, et donc de voir rapidement l'évolution de l'objet sur le site. En effet, chaque action effectuée via l'administration Django est inscrite dans un journal des actions.

Historique des modifications d'un objet utilisateur
Historique des modifications d'un objet utilisateur

De même, sur l'index vous avez la liste de vos dernières actions, vous permettant de voir ce que vous avez fait récemment, et d'accéder rapidement aux liens, en cas d'erreur par exemple.

Administrons nos propres modèles

Pour le moment, nous avons vu comment manipuler les données des objets de base de Django, ceux concernant les utilisateurs. Il serait pratique désormais de faire de même avec nos propres modèles. Comme dit précédemment, l'administration est auto-générée : vous n'aurez pas à écrire beaucoup de lignes pour obtenir le même résultat que ci-avant. En réalité, quatre lignes suffisent : dans le fichier blog/admin.py, insérez ces lignes :

from django.contrib import admin
from .models import Categorie, Article

admin.site.register(Categorie)
admin.site.register(Article)

Ici, nous indiquons à Django de prendre en compte les modèles ArticleetCatégoriedans l'administration. Rafraîchissez la page (relancez le serveur Django si nécessaire) et vous devez voir apparaître une nouvelle section, pour notre blog, semblable à la figure suivante.

La deuxième section nous permet enfin de gérer notre blog !
La deuxième section nous permet enfin de gérer notre blog !

Les fonctionnalités sont les mêmes que celles pour les utilisateurs : nous pouvons éditer des articles, des catégories, les supprimer, consulter l'historique, etc. Vous pouvez désormais créer vos articles depuis cette interface et voir le résultat depuis les vues que nous avons créées précédemment.
Comme vous pouvez le voir, l'administration prend en compte la clé étrangère de la catégorie.

Comment cela fonctionne-t-il ?

Au lancement du serveur, le framework va chercher dans chaque application installée (celles qui sont listées dans INSTALLED_APPS) le fichier admin.py, et si celui-ci existe exécutera son contenu.
Ainsi, si nous souhaitons activer l'administration pour toutes nos applications, il suffit de créer un fichieradmin.py  dans chacune, et d'appeler la méthode admin.site.register()  sur chacun de nos modèles.
Nous pouvons alors deviner que le module django.contrib.auth  contient son propre fichieradmin.py, qui génère l'administration des utilisateurs et des groupes.

Personnalisons l'administration

Avant tout, créez quelques articles depuis l'administration, si ce n'est déjà fait. Cela vous permettra de tester tout au long de ce chapitre les différents exemples qui seront donnés.

Modifier l'aspect des listes

Dans un premier temps, nous allons voir comment améliorer la liste. En effet, pour le moment, nos listes sont assez vides, comme vous pouvez le constater sur la figure suivante.

Notre liste d'articles, avec uniquement le titre comme colonne
Notre liste d'articles, avec uniquement le titre comme colonne

Le tableau ne contient qu'une colonne contenant le titre de notre article. Cette colonne n'est pas due au hasard : c'est en réalité le résultat de la méthode __str__  que nous avons définie dans notre modèle.

class Article(models.Model):
    titre = models.CharField(max_length=100)
    auteur = models.CharField(max_length=42)
    slug = models.SlugField(max_length=100)
    contenu = models.TextField()
    date = models.DateTimeField(auto_now_add=True, auto_now=False, 
                                verbose_name="Date de parution")
    categorie = models.ForeignKey(Categorie)
    
    class Meta:
        verbose_name = "article"
        ordering = ['date']

    def __str__(self):
        return self.titre

Ce résultat par défaut est assez utile, mais nous aimerions pouvoir gérer plus facilement nos articles : les trier selon certains champs, filtrer par catégorie, etc. Pour ce faire, nous devons créer une nouvelle classe dans notre fichier admin.py, contenant actuellement ceci :

from django.contrib import admin
from blog.models import Categorie, Article

admin.site.register(Categorie)
admin.site.register(Article)

Nous allons donc créer une nouvelle classe pour chaque modèle. Notre classe héritera deadmin.ModelAdmin  et aura principalement 5 attributs, listés dans le tableau suivant :

Nom de l'attribut

Utilité

list_display

Liste des champs du modèle à afficher dans le tableau

list_filter

Liste des champs à partir desquels nous pourrons filtrer les entrées

date_hierarchy

Permet de filtrer par date de façon intuitive

ordering

Tri par défaut du tableau

search_fields

Configuration du champ de recherche

Nous pouvons dès lors rédiger notre première classe adaptée au modèleArticle:

class ArticleAdmin(admin.ModelAdmin):
   list_display   = ('titre', 'auteur', 'date')
   list_filter    = ('auteur','categorie',)
   date_hierarchy = 'date'
   ordering       = ('date', )
   search_fields  = ('titre', 'contenu')

Ces attributs définissent les règles suivantes :

  • Le tableau affiche les champs titreauteur  et date. Notez que les en-têtes sont nommés selon leur attribut verbose_name  respectif.

  • Il est possible de filtrer selon les différents auteurs et la catégorie des articles (menu de droite).

  • L'ordre par défaut est la date de parution, dans l'ordre croissant (du plus ancien au plus récent).

  • Il est possible de chercher les articles contenant un mot, soit dans leur titre, soit dans leur contenu.

  • Enfin, il est possible de voir les articles publiés sur une certaine période (première ligne au-dessus du tableau).

Désormais, il faut spécifier à Django de prendre en compte ces données pour le modèle Article. Pour ce faire, modifions la ligne admin.site.register(Article), en ajoutant un deuxième paramètre :

admin.site.register(Article, ArticleAdmin)

Avec ce deuxième argument, Django prendra en compte les règles qui ont été spécifiées dans la classeArticleAdmin.

from django.contrib import admin
from .models import Categorie, Article

class ArticleAdmin(admin.ModelAdmin):
    list_display   = ('titre', 'auteur', 'date')
    list_filter    = ('auteur', 'categorie',)
    date_hierarchy = 'date'
    ordering       = ('date', )
    search_fields  = ('titre', 'contenu')

admin.site.register(Categorie)
admin.site.register(Article, ArticleAdmin)

Vous pouvez maintenant observer le résultat sur la figure suivante :

La même liste, bien plus complète, et plus pratique !
La même liste, bien plus complète, et plus pratique !

Les différents changements opérés sont désormais visibles. Vous pouvez bien sûr modifier selon vos besoins : supprimer une colonne, changer le tri...

Pour terminer, nous allons voir comment créer des colonnes plus complexes. Il peut arriver que vous ayez envie d'afficher une colonne après un certain traitement. Par exemple, afficher les 40 premiers caractères de notre article. Pour ce faire, nous allons devoir créer une méthode dans notre ModelAdmin, qui va se charger de renvoyer ce que nous souhaitons, et la lier à notre list_display.

Créons tout d'abord notre méthode. Celles de notreModelAdmin  auront toujours la même structure :

from django.utils.text import Truncator

def apercu_contenu(self, article):
    """ 
    Retourne les 40 premiers caractères du contenu de l'article, 
    suivi de points de suspension si le texte est plus long. 
    
    On pourrait le coder nous même, mais Django fournit déjà la 
    fonction qui le fait pour nous !
    """
    return Truncator(article.contenu).chars(40, truncate='...')

La méthode prend en argument l'instance de l'article, et nous permet d'accéder à tous ses attributs. Ensuite, il suffit d'exécuter quelques opérations, puis de renvoyer une chaîne de caractères. Il faut ensuite intégrer cela dans notre ModelAdmin.

Pour l'utiliser dans list_display, on peut traiter la fonction comme un champ. Il suffit donc d'ajouter'apercu_contenu'  à la liste, Django s'occupe du reste. Pour ce qui est de l'en-tête, il faudra par contre ajouter une ligne supplémentaire pour spécifier le titre de la colonne :

from django.contrib import admin
from django.utils.text import Truncator

from blog.models import Categorie, Article

class ArticleAdmin(admin.ModelAdmin):
    list_display   = ('titre', 'categorie', 'auteur', 'date', 'apercu_contenu')
    list_filter    = ('auteur','categorie', )
    date_hierarchy = 'date'
    ordering       = ('date', )
    search_fields  = ('titre', 'contenu')

    def apercu_contenu(self, article):
        """ 
        Retourne les 40 premiers caractères du contenu de l'article, 
        suivi de points de suspension si le texte est plus long. 
        """
        return Truncator(article.contenu).chars(40, truncate='...')

    # En-tête de notre colonne
    apercu_contenu.short_description = 'Aperçu du contenu'

admin.site.register(Categorie)
admin.site.register(Article, ArticleAdmin)

Nous obtenons notre nouvelle colonne avec les premiers mots de chaque article (voir la figure suivante).

La liste des articles est accessible depuis l'administration
La liste des articles est accessible depuis l'administration

Modifier le formulaire d'édition

Nous allons désormais nous occuper du formulaire d'édition. Pour le moment, comme vous pouvez le voir sur la figure suivante, nous avons un formulaire affichant tous les champs :

Le formulaire d'édition d'un article par défaut
Le formulaire d'édition d'un article par défaut

L'ordre d'apparition des champs dépend actuellement de l'ordre de déclaration dans notre modèle. Nous allons ici séparer le contenu des autres champs.
Tout d'abord, modifions l'ordre via un nouvel attribut dans notre ModelAdmin  : fields. Cet attribut prend une liste de champs, qui seront affichés dans l'ordre souhaité. Cela nous permettra de cacher des champs (inutile dans le cas présent) et, bien évidemment, de changer leur ordre :

fields = ('titre', 'auteur', 'categorie', 'contenu')

Nous observons peu de changements : le champ Catégorie est désormais au-dessus du champ de contenu et la date ne devrait plus apparaitre (elle est auto-remplie de toute manière).

Pour le moment, notre formulaire est dans un unique fieldset (ensemble de champs). Conséquence : tous les champs sont les uns à la suite des autres, sans distinction. Nous pouvons hiérarchiser cela en utilisant un attribut plus complexe que fields.
À titre d'exemple, nous allons mettre les champstitre,auteur  et categorie  dans un fieldset etcontenu  dans un autre.

fieldsets = (
    # Fieldset 1 : meta-info (titre, auteur…)
   ('Général', {
        'classes': ['collapse',],
        'fields': ('titre', 'auteur', 'categorie')
    }),
    # Fieldset 2 : contenu de l'article
    ('Contenu de l\'article', {
       'description': 'Le formulaire accepte les balises HTML. Utilisez-les à bon escient !',
       'fields': ('contenu', )
    }),
)

Voyons pas à pas la construction de ce tuple :

  1. Nos deux éléments dans le tuple fieldset, qui correspondent à nos deux fieldsets distincts.

  2. Chaque élément contient un tuple contenant exactement deux informations : son nom, et les informations sur son contenu, sous forme de dictionnaire.

  3. Ce dictionnaire contient trois types de données :

    1. fields  : liste des champs à afficher dans le fieldset ;

    2. description  : une description qui sera affichée en haut du fieldset, avant le premier champ ;

    3. classes  : des classes CSS supplémentaires à appliquer sur le fieldset (par défaut il en existe trois :wideextrapretty  et collapse).

Ici, nous avons donc séparé les champs en deux fieldsets et affiché quelques informations supplémentaires pour aider à la saisie. Au final, nous avons le fichier admin.py  suivant :

from django.contrib import admin
from blog.models import Categorie, Article

class ArticleAdmin(admin.ModelAdmin):

    # Configuration de la liste d'articles
    list_display   = ('titre', 'categorie', 'auteur', 'date')
    list_filter    = ('auteur','categorie', )
    date_hierarchy = 'date'
    ordering       = ('date', )
    search_fields  = ('titre', 'contenu')

    # Configuration du formulaire d'édition
    fieldsets = (
        # Fieldset 1 : meta-info (titre, auteur…)
       ('Général', {
            'classes': ['collapse', ],
            'fields': ('titre', 'auteur', 'categorie')
        }),
        # Fieldset 2 : contenu de l'article
        ('Contenu de l\'article', {
           'description': 'Le formulaire accepte les balises HTML. Utilisez-les à bon escient !',
           'fields': ('contenu', )
        }),
    )

    # Colonnes personnalisées 
    def apercu_contenu(self, article):
        """ 
        Retourne les 40 premiers caractères du contenu de l'article. S'il
        y a plus de 40 caractères, il faut rajouter des points de suspension.
        """
        text = article.contenu[0:40]
        if len(article.contenu) > 40:
            return '%s…' % text
        else:
            return text

    apercu_contenu.short_description = 'Aperçu du contenu'

admin.site.register(Categorie)
admin.site.register(Article, ArticleAdmin)

… qui donne la figure suivante.

Notre formulaire, mieux présenté qu'avant
Notre formulaire, mieux présenté qu'avant

Retour sur notre problème de slug

Souvenez-vous, au chapitre précédent nous avons parlé des slugs, ces chaînes de caractères qui permettent d'identifier un article dans notre URL. Dans notre zone d'administration, ce champ est actuellement ignoré… Nous souhaitons toutefois le remplir, mais en plus que cela se fasse automatiquement !

Nous avons notre champ slug  que nous pouvons désormais éditer à la main. Mais nous pouvons aller encore plus loin, en ajoutant une option qui remplit instantanément ce champ grâce à un script JavaScript. Pour ce faire, il existe un attribut aux classes ModelAdmin  nommé prepopulated_fields. Ce champ a pour principal usage de remplir les champs de type SlugField  en fonction d'un ou plusieurs autres champs :

prepopulated_fields = {'slug': ('titre', ), }

Ici, notre champslug  est rempli automatiquement en fonction du champ titre. Il est possible bien entendu de concaténer plusieurs chaînes, si vous voulez par exemple faire apparaître l'auteur.

Exemple d'utilisation de prepopulated_fields
Exemple d'utilisation de prepopulated_fields

En résumé

  • L'administration est un outil optionnel : il est possible de ne pas l'utiliser. Une fois activée, de très nombreuses options sont automatisées, sans qu'il y ait besoin d'ajouter une seule ligne de code !

  • Ce module requiert l'usage de l'authentification, et la création d'un super-utilisateur afin d'en restreindre l'accès aux personnes de confiance.

  • De base, l'administration permet la gestion complète des utilisateurs, de groupes et des droits de chacun, de façon très fine.

  • L'administration d'un modèle créé dans une de nos applications est possible en l'enregistrant dans le module d'administration, via admin.site.register(MonModele)  dans le fichieradmin.py  de l'application.

  • Il est également possible de personnaliser cette interface pour chaque module, en précisant ce qu'il faut afficher dans les tableaux de listes, ce qui peut être édité, etc.

Example of certificate of achievement
Example of certificate of achievement