Management commands - commands from the command line using the manage.py script.
The most frequent areas of application are actions performed one-time or periodically, but for which, for some reason, launch through the scheduler is not available. For example, sending users one-time messages, retrieving a selection of data from the database, checking the availability of the necessary files and folders before rolling updates, quickly creating model objects during development, etc.
The basics
Commands are created in the application directories (applications must be added to INSTALED_APPS), in the app / management / commands subdirectory. A separate file is created for each command. Files other than those beginning with an underscore will be available from the command line.
app/ __init__.py management/ __init__.py commands/ __init__.py _tools.py zen.py
In this example, the zen command will be available, but _tools will not.
Commands are created by inheriting from the django.core.management.base.BaseCommand class. In the simplest case, it suffices to rewrite the function handle. This command will be executed, and the result returned by it will be printed on the console.
from django.core.management.base import BaseCommand class Command(BaseCommand): help = 'The Zen of Python' def handle(self, *args, **options): import this
Let's try to call our team:
python manage.py zen The Zen of Python, by Tim Peters Beautiful is better than ugly. ...
The attribute of the class help is a description that is displayed when calling a command with the key --help or if the command is entered incorrectly.
$ python manage.py zen --help usage: manage.py zen [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] The Zen of Python optional arguments: -h, --help show this help message and exit --version show program's version number and exit -v {0,1,2,3}, --verbosity {0,1,2,3} Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output --settings SETTINGS The Python path to a settings module, eg "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used. --pythonpath PYTHONPATH A directory to add to the Python path, eg "/home/djangoprojects/myproject". --traceback Raise on CommandError exceptions --no-color Don't colorize the command output.
Argument parsing
As we can see, our team already takes 7 arguments.
But what if this is not enough for us and we want to add our options? To do this, we need to create the function add_arguments in our class, where we list all the arguments that we want to pass to our team. Each argument is created by calling the parser.add_argument function with a number of parameters.
Suppose we are not satisfied with the long output of our function and we want the -s and --short keys to print just Hello world:
from django.core.management.base import BaseCommand class Command(BaseCommand): help = 'The Zen of Python' def handle(self, *args, **options): if options['short']: import __hello__ else: import this def add_arguments(self, parser): parser.add_argument( '-s', '--short', action='store_true', default=False, help=' ' )
This file when called with the -s option will print Hello world.
$ python manage.py zen -s Hello world... (coolwriter)$ python manage.py zen The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
Let's take a closer look at how argument parsing is set.
The parser is inherited from argparse.ArgumentParser, and the arguments taken by the add_argument function can be found in the documentation for the argparse library in the python documentation. The most important are:
name or flags - the name or list of names and labels. We have this 'short', '-s' and '--short'.
action - what to do with the argument value. The most interesting (but not all) options are as follows:
store - save as the value of our option. If several key-value pairs are transmitted, the value of the last
store_const - save the constant value in the name key. The constant is passed as an argument to
const of the same function add_argument.
For example:
parser.add_argument('my_option', action='store_const', const=1234)
The handle functions in options will be passed to 'my_option': 1234
store_true, store_false - special cases of the previous option. True or False value is saved
append - the value will be appended to the end of the list
append_const is the same as the previous one, but the value passed to the
const argument (which can be any object) is appended
nargs is the number of arguments. Possible values: integer, '?' - one or the default value from the default argument, '*' - all as many as there are, and are collected into the list, '+' - at least one, and if several are assembled into the list, argparse.REMAINDER - all remaining arguments from the command line are collected there . Incompatible with action = const
Note: if you use this argument, the value of your option from the command line will be transferred to the handle as a list, even if there is only one element. (At the same time, the default value is passed as is, without being reduced to the list.)
default is the
default value.
type - casting the argument to the specified type.
choices - limiting the options for the value of the argument. The value of choices is passed a list of possible values.
required is a required argument.
help - A description of what this argument does.
dest - if you want to save your option under a different name, you can specify dest = 'my_new_name'. Otherwise, the name of the argument will be used.
These arguments will be further passed to the handle function in the form of the options dictionary.
But what if we want to pass unnamed arguments to handle?
In this case, add_arguments to get all unnamed arguments in the args option. For example, if we want to pass several integers to a command:
def add_arguments(self, parser): parser.add_argument( nargs='+', type=int, dest = 'args' )
Execution order
The command is executed in the following order:
- First, the run_from_argv () method is called. This method creates a parser through a call to create_parser, and the created parser adds default arguments (of type no-color), and also calls the add_arguments method, thus adding all the options we created.
- After that, the execute function is called. This function performs several checks, and then runs the function handle. The result of the execution of handle is printed to standard output.
Of course, any of these functions can be customized. For example, let's make a nice multi-line help message:
from argparse import RawTextHelpFormatter def create_parser(self, prog_name, subcommand): parser = super(Command, self).create_parser(prog_name, subcommand) parser.formatter_class = RawTextHelpFormatter return parser
Here, perhaps, is all that is needed for writing management commands in most cases.
Conclusion
The article does not claim to be a complete overview of all the possibilities for creating management commands - they are described in the Django documentation. Those interested can contact
documentation .
Parsing command line arguments there, alas, is practically not disclosed. Those wishing to immerse themselves in the subtleties of this issue should examine the python documentation.
Argparse module