commande – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Ecrire une commande Django http://sametmax.com/ecrire-une-commande-django/ http://sametmax.com/ecrire-une-commande-django/#comments Wed, 04 Dec 2013 07:01:44 +0000 http://sametmax.com/?p=7729 manage.py : c'est portable d'un projet à l'autre et ça permet d'utiliser l'ORM et les templates sans réglage puisqu'on a accès à tous les settings, automatiquement.]]> Quand vous avez à faire un script pour un projet Django, il est pratique de l’avoir sous forme de sous-commande de manage.py : c’est portable d’un projet à l’autre et ça permet d’utiliser l’ORM et les templates sans réglage puisqu’on a accès à tous les settings, automatiquement.

Malheureusement le wrapper de Django destiné à cela date un peu, il est plutôt lourd, pas très souple et utilise des pratiques qui ne sont plus au goût du jour depuis quelques années. Rien de rédhibitoire, mais tout de même.

D’abord, il faut placer sa commande dans un fichier portant le nom de la commande, et dans un package management.commands d’une de vos apps.

Par exemple, si vous voulez faire une commande “nettoyer_godmichets” dans l’application “sex_shop”, il faudra la mettre bien profondément dans le tréfonds de votre projet :

racine
│   ├── sex_shop
│   │   ├── management
│   │   │   ├── commands
│   │   │   │   ├── nettoyer_godmichets.py
│   │   │   │   ├── __init__.py
│   │   │   │   └── __init__.pyc
│   │   │   ├── __init__.py

Notez les fichiers __init__.py, indispendables sinon votre commande ne sera pas trouvée. Oh, et ‘sex_shop’ doit être dans INSTALLED_APPS.

Ensuite, votre commande doit être une classe héritant de BaseCommand. Sa méthode handle() sera appelée automatiquement au lancement de la commande.

from django.core.management.base import BaseCommand
from sex_shop.models import Godmichet

class Command(BaseCommand):

    def handle(self, *args, **options):
        for god in Godmichet.objects.all():
            god.clean()

Et vous pouvez lancer la commande :

./manage.py nettoyer_godmichets

Néanmoins généralement on voudra avoir un peu de décorum.


from optparse import make_option

from django.core.management.base import BaseCommand
from sex_shop.models import Godmichet, Marque


class Command(BaseCommand):

    # ici on peut mettre un message d'aide
    help = 'Fait briller dard dard les dards'

    # optionellement une aide pour les arguments
    args = 'marque1, [marque2], marque3'

    # On peut ajouter des options passables à la commande
    option_list = BaseCommand.option_list + (
        make_option('--dry-run',
            action='store_true',
            dest='dry_run',
            default=False,
            help='Affichage uniquement, aucune action réelle'),
        )

    def handle(self, *args, **options):

        # on retrouve dans args les arguments positionnels de la commande

        if not args:
            for god in Godmichet.objects.all():
                # Plutôt que print(), on peut utiliser ce wrapper
                # pour ecrire sur le terminal. Cela permet de bénéficier
                # automatiquement de l'option --verbosity
                self.stdout.write('Processing %s' % god.name)

                # La valeur des options est passée via kwargs.
                if not options['dry_run']:
                    god.clean()
        else:
            # l'utilisateur a passé des marques ? On nettoie que les gods
            # de ces marques...
            for marque in args:
                try:
                    gods = Marque.objects.get(name=marque).gods.all()
                    for god in gods:
                        self.stdout.write('Processing %s' % god.name)

                        if not options['dry_run']:
                            god.clean()

                except Marque.DoesNotExist:
                    # si la marque n'existe pas, on fait une erreur
                    # ceci arrête le script, retourne un code d'erreur 1
                    # et met le texte en rouge
                    raise CommandError('La marque %s n'existe pas' %s marque)

Et voilà, votre commande accepte maintenant optionnellement qu’on lui passe une liste de marques et/ou une option --dry-run:

./manage.py nettoyer_godmichet devilmaycry choucroutebestfriend --dry-run

En plus de ça, la commande accepte automatiquement :

  • --help
  • --verbosity
  • --settings
  • --pythonpath

Qui ont le même effet que sur toutes les commandes django officielles.

]]>
http://sametmax.com/ecrire-une-commande-django/feed/ 5 7729