Commandes personnalisées Django : les management commands

Les frameworks web permettent de servir des pages web. Mais il est parfois utile voire nécessaire d'exécuter des programmes sans passer par un navigateur, par exemple dans des tâches planifiées (CRON…) ou manuellement via la ligne de commande. Django vient avec un outil puissant pour ceci : les management commands.

Management commands : c'est quoi ?

Vous avez tous utilisé des management commands… celles fournies avec Django ! En voici quelques exemples : python manage.py runserver pour démarrer le serveur de dev, python manage.py syncdb pour créer les tables de BDD, python manage.py test pour lancer les tests, etc.

Imaginez maintenant que vous puissiez définir vos propres commandes, du genre python manage.py ma_commande : c'est ce que vous propose Django !

Écriture d'une commande django-admin personnalisée

Nous allons voir ci-dessous comment créer une commande très simple (et qui plus est, il faut bien l'avouer, pas très utile…) : il permettra d'afficher la liste des backlogs. L'essentiel est que vous compreniez le principe, pour ensuite construire vos propres commandes.

Bien entendu, les commandes django-admin custom sont des programmes Python comme les autres.

Où stocker les scripts ?

Les commandes personnalisées sont stockées dans un module nommé management/commands, situé dans le répertoire d'une application.

Dans le répertoire de notre application chistera, créons donc une telle arborescence (sans oublier d'ajouter les fichiers __init__.py) :

miage_scrum
|--- manage.py
|--- miage_scrum/
|--- chistera
|    |--- __init__.py
|    |--- models.py
|    |--- views.py
|    |--- tests.py
|    |--- management
|    |    |--- __init__.py
|    |    |--- commands
|    |    |    |--- __init__.py
|    |    |    |--- backlogs_list.py

Écriture de la commande à proprement parler

OK, notre arborescence est prête. Nous allons à présent éditer le fichier backlogs_list.py :

chistera/management/commands/backlog_list.py
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    args = '<team_id>'
    help = 'Affiche la liste des backlogs'

    def handle(self, *args, **options):
        self.stdout.write('Coucou !')

Comme vous le constatez, l'implémentation d'une commande personnalisée est très simple : il suffit de déclarer une classe Command qui hérite de la classe Django BaseCommand, comportant une méthode handle() implémente le code de la commande à proprement parler. Dans cette première version, notre commande affichera simplement « Coucou ! » à l'écran.

Remarquez les attributs args et help de la classe, qui permettent de spécifier des chaînes d'aide pour notre commande (cf. ci-dessous).

Terminal
$ cd miage_scrum

$ python manage.py
Usage: manage.py subcommand [options] [args]
...
[chistera]
    backlogs_list

$ python manage.py backlogs_list --help
Usage: manage.py backlogs_list [options] <team_id>
Affiche la liste des backlogs

$ python manage.py backlogs_list
Coucou !

Notre commande complète

Complétons notre commande pour qu'elle réalise l'action attendue : afficher la liste des backlogs. Il sera possible de passer un argument à notre commande : l'identifiant de l'objet Team si l'on souhaite n'afficher que les backlogs d'une équipe particulière.

chistera/management/commands/backlog_list.py
from django.core.management.base import BaseCommand

from chistera.models import ProductBacklog

class Command(BaseCommand):
    args = '<team_id>'
    help = 'Affiche la liste des backlogs'

    def handle(self, *args, **options):
        try:
            team_id = int(args[0])
            backlogs = ProductBacklog.objects.filter(team__id=team_id)
        except:
            backlogs = ProductBacklog.objects.all()

        for backlog in backlogs:
            self.stdout.write(backlog.name)
Terminal
$ python manage.py backlogs_list
Front office
Back office
$ python manage.py backlogs_list 2
Back office