Les applications peuvent inscrire leurs propres actions auprès de manage.py. Par exemple, il pourrait être utile d’ajouter une action manage.py pour une application Django que vous distribuez. Dans ce document, nous allons créer un commande personnalisée closepoll pour l’application polls écrite dans le tutoriel.
Pour cela, ajoutons simplement un répertoire management/commands dans l’application. Django inscrit une commande manage.py pour chaque module Python dans ce répertoire dont le nom ne commence pas par un soulignement. Par exemple :
polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py
Dans cet exemple, la commande closepoll sera disponible dans tout projet qui inclut l’application polls dans son réglage INSTALLED_APPS.
Le module _private.py ne sera pas disponible en tant que commande de gestion.
Le module closepoll.py n’a qu’une seule exigence : il doit définir une classe Command comme sous-classe de BaseCommand ou l’une de ses sous-classes.
Scripts autonomes
Les commandes de gestion personnalisées sont particulièrement utiles pour exécuter des scripts autonomes ou pour des scripts qui sont programmés pour s’exécuter périodiquement par l’intermédiaire du crontab Unix ou du panneau de configuration des tâches planifiées de Windows.
Pour implémenter la commande, modifiez polls/management/commands/closepoll.py comme ceci :
from django.core.management.base import BaseCommand, CommandError
from polls.models import Poll
class Command(BaseCommand):
args = '<poll_id poll_id ...>'
help = 'Closes the specified poll for voting'
def handle(self, *args, **options):
for poll_id in args:
try:
poll = Poll.objects.get(pk=int(poll_id))
except Poll.DoesNotExist:
raise CommandError('Poll "%s" does not exist' % poll_id)
poll.opened = False
poll.save()
self.stdout.write('Successfully closed poll "%s"' % poll_id)
Note
Quand vous utilisez des commandes de gestion et que vous souhaitez afficher des informations en console, vous devriez utiliser les méthodes self.stdout et self.stderr plutôt que d’utiliser directement stdout et stderr. En utilisant ces méthodes intermédiaires, il devient beaucoup plus simple de tester vos commandes personnalisées. Notez aussi que vous n’avez pas besoin de terminer vos messages avec un caractère de saut de ligne car il sera ajouté automatiquement, sauf si vous indiquez le paramètre ending:
self.stdout.write("Unterminated line", ending='')
La nouvelle commande personnalisée peut être appelée en utilisant python manage.py closepoll <poll_id>.
La méthode handle() reçoit zéro ou plusieurs poll_ids et définit poll.opened à False pour chacun d’eux. Si l’utilisateur indique des identifiants qui n’existent pas, une erreur CommandError est levée. L’attribut poll.opened n’existe pas dans le tutoriel, elle a été ajoutée à polls.models.Poll pour cet exemple.
La même commande closepoll pourrait aisément être modifiée afin de supprimer un sondage donné au lieu de le fermer, en acceptant des options supplémentaires en ligne de commande. Ces options personnalisées doivent être ajoutées à option_list de cette façon :
from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--delete',
action='store_true',
dest='delete',
default=False,
help='Delete poll instead of closing it'),
)
def handle(self, *args, **options):
# ...
if options['delete']:
poll.delete()
# ...
L’option (delete dans notre exemple) est disponible dans le paramètre dictionnaire options de la méthode handle(). Consultez la documentation Python de optparse pour en savoir plus sur l’utilisation de make_option.
En plus de pouvoir ajouter des options de ligne de commande personnalisées, toutes les commandes de gestion acceptent certaines options par défaut, telles que --verbosity et --traceback.
Commandes de gestion et langues
La méthode BaseCommand.execute() définit en dur la locale en-us car les commandes fournies par Django effectuent plusieurs tâches qui exigent une langue système neutre (sans traduction, d’où le choix de ), par exemple le rendu de contenu utilisateur ou le remplissage de la base de données.
Si votre commande de gestion utilise une autre locale, c’est à vous de l’activer et de la désactiver manuellement dans votre méthode handle() ou handle_noargs() en utilisant les fonctions offertes par le code de prise en charge de l’internationalisation :
from django.core.management.base import BaseCommand, CommandError
from django.utils import translation
class Command(BaseCommand):
...
can_import_settings = True
def handle(self, *args, **options):
# Activate a fixed locale, e.g. Russian
translation.activate('ru')
# Or you can activate the LANGUAGE_CODE
# chosen in the settings:
#
#from django.conf import settings
#translation.activate(settings.LANGUAGE_CODE)
# Your command logic here
# ...
translation.deactivate()
Soyez toutefois conscient que les commandes de gestion système doivent être très prudentes quand elles sont lancées avec des locales changeantes, ainsi :
Assurez-vous que le réglage USE_I18N est toujours True lorsque la commande fonctionne (c’est un bon exemple des problèmes possibles dus à un environnement d’exécution dynamique, ce que les commandes Django évitent en utilisant toujours la même locale).
Révisez le code de votre commande et le code qu’elle appelle quant à des différences de comportement lorsque les locales sont modifiées et évaluez l’impact potentiel sur le comportement prévisible de votre commande.
La classe de base dont toutes les autres commandes de gestion héritent.
Utilisez cette classe si vous souhaitez accéder à tous les mécanismes qui analysent les paramètres de ligne de commande et qui aiguillent sur le code à appeler en conséquence. Si vous n’avez pas besoin de modifier ce comportement, considérez l’utilisation de l’une de ses sous-classes.
L’héritage direct de la classe BaseCommand exige que vous implémentiez la méthode handle().
Tous les attributs peuvent être définis dans votre sous-classe et peuvent être utilisés dans les sous-classes de BaseCommand.
Une chaîne énumérant les paramètres acceptés par la commande, adaptée à l’utilisation des message d’aide ; par exemple, une commande qui accepte une liste de noms d’applications pourrait définir cette chaîne à ‘<nom_app nom_app ...>’.
Une valeur booléenne indiquant si la commande doit pouvoir importer les réglages Django. Si True, execute() vérifiera que c’est bel et bien possible avant de continuer. La valeur par défaut est
Une brève description de la commande, qui sera affichée dans le message d’aide lorsque l’utilisateur lance la commande python manage.py help <commande>.
Une liste des options optparse qui seront transmises dans l’OptionParser de la commande pour l’analyse des paramètres.
Une valeur booléenne indiquant si la commande affiche des commandes SQL ; si True, le contenu en sortie est automatiquement entouré des instructions BEGIN; et COMMIT;. La valeur par défaut est
Une valeur booléenne ; si True, les modèles installés seront validés avant l’exécution de la commande elle-même. La valeur par défaut est True. Pour valider les modèles d’une seule application plutôt que les modèles de toutes les applications, appelez vous-même validate() à partir de handle().
BaseCommand contient quelques méthodes qui peuvent être surchargées, mais seule la méthode handle() doit absolument être implémentée.
Implémentation d’un constructeur dans une sous-classe
Si vous implémentez __init__ dans votre sous-classe de BaseCommand, vous devez appeler la méthode __init__ de BaseCommand.
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs)
# ...
Renvoie la version de Django, qui devrait être correcte pour toutes les commandes intégrées de Django. Les commandes fournies par les applications non Django peuvent surcharger cette méthode pour retourner leur propre version.
Essaie d’exécuter cette commande en effectuant la validation des modèles au besoin (selon la valeur de l’attribut requires_model_validation). Si la commande lève une erreur CommandError, elle l’intercepte et l’affiche proprement à destination de stderr.
Appel d’une commande gestion depuis son propre code
execute() ne devrait pas être appelée directement depuis votre code pour lancer une commande. Utilisez plutôt call_command.
Le corps de la logique de votre commande. Les sous-classes doivent implémenter cette méthode.
Valide l’application indiquée, levant CommandError en cas d’erreur.
Si app vaut None, toutes les applications installées sont validées.
Une commande de gestion qui accepte en paramètre un ou plusieurs noms d’applications installées, et applique un traitement à chacune d’elles.
Plutôt que d’implémenter handle(), les sous-classes doivent implémenter handle_app() qui sera appelée une fois pour chaque application.
Effectue les actions de la commande pour app, qui sera le module Python correspondant au nom d’application passé à la ligne de commande.
Une commande de gestion qui accepte un ou plusieurs paramètres arbitraires (labels) en ligne de commande et effectue une opération pour chacun d’eux.
Plutôt que d’implémenter handle(), les sous-classes doivent implémenter handle_label() qui sera appelée une fois pour chaque paramètre (label).
Effectue les actions de la commande pour label, qui sera la chaîne telle que passée à la ligne de commande.
Une commande qui n’accepte aucun paramètre en ligne de commande.
Plutôt que d’implémenter handle(), les sous-classes doivent implémenter handle_noargs() ; handle() est elle-même surchargée pour s’assurer qu’aucun paramètre n’est passé à la ligne de commande.
Effectue les actions de cette commande.
Classe d’exception indiquant qu’un problème est survenu lors de l’exécution de la commande de gestion.
Si cette exception est levée durant l’exécution d’une commande de gestion à partir de la console en ligne de commande, elle sera interceptée et transformée en un message d’erreur proprement affiché à destination du flux de sortie approprié (par ex. stderr). En conséquence, le déclenchement de cette exception (accompagné d’une description significative de l’erreur) est la manière privilégiée de signaler que quelque chose s’est mal passé durant l’exécution d’une commande.
Si une commande de gestion est appelée depuis du code par l’intermédiaire de call_command, c’est alors à vous d’intercepter cette exception si nécessaire.
Jan 13, 2016