Ticket #9170: management-commands-9170.diff

File management-commands-9170.diff, 9.7 KB (added by davidfischer, 6 years ago)

Added a complete tutorial of adding a management command

  • docs/howto/custom-management-commands.txt

    11.. _howto-custom-management-commands:
    34Writing custom django-admin commands
    89Applications can register their own actions with ``manage.py``. For example,
    910you might want to add a ``manage.py`` action for a Django app that you're
    10 distributing.
     11distributing. In this document, we will be building a custom ``closepoll``
     12command for the ``polls`` application from :ref:`tutorial 1<intro-tutorial01>`.
    12 To do this, just add a ``management/commands`` directory to your application.
     14To do this, just add a ``management/commands`` directory to the application.
    1315Each Python module in that directory will be auto-discovered and registered as
    1416a command that can be executed as an action when you run ``manage.py``::
    16     blog/
     18    polls/
    1719        __init__.py
    1820        models.py
    1921        management/
    2022            __init__.py
    2123            commands/
    2224                __init__.py
    23                 explode.py
     25                closepoll.py
     26        tests.py
    2427        views.py
    26 In this example, the ``explode`` command will be made available to any project
    27 that includes the ``blog`` application in ``settings.INSTALLED_APPS``.
     29In this example, the ``closepoll`` command will be made available to any project
     30that includes the ``polls`` application in :setting:`INSTALLED_APPS`.
    29 The ``explode.py`` module has only one requirement -- it must define a class
    30 called ``Command`` that extends ``django.core.management.base.BaseCommand``.
     32The ``closepoll.py`` module has only one requirement -- it must define a class
     33``Command`` that extends :class:`BaseCommand` or one of its
    32 For more details on how to define your own commands, look at the code for the
    33 existing ``django-admin.py`` commands, in ``/django/core/management/commands``.
    34  No newline at end of file
     36.. admonition:: Standalone scripts
     38  Custom management commands are especially useful for running standalone
     39  scripts or for scripts that are periodically executed from the UNIX crontab
     40  or from Windows scheduled tasks control panel.
     42To implement the command, edit ``polls/management/commands/closepoll.py`` so
     43it looks like this:
     45.. code-block:: python
     47    from django.core.management.base import BaseCommand, CommandError
     48    from example.polls.models import Poll
     50    class Command(BaseCommand):
     51        args = "<poll_id poll_id ...>"
     52        help = "Closes the specified poll for voting"
     54        def handle(self, *args, **options):
     55            for poll_id in args:
     56                try:
     57                    poll = Poll.objects.get(pk=int(poll_id))
     58                except Poll.DoesNotExist:
     59                    raise CommandError('Poll "%s" does not exist' %poll_id)
     61                poll.opened = False
     62                poll.save
     64                print 'Successfully closed poll "%s"' %poll_id
     66The new custom command can be called using ``python manage.py closepoll
     69The ``handle()`` method takes zero or more ``poll_ids`` and sets ``poll.opened``
     70to ``False`` for each one. If the user referenced any nonexistant polls, a
     71:class:`CommandError` is raised. The ``poll.opened`` attribute does not exist
     72in the :ref:`tutorial<intro-tutorial01>` and was added to
     73``polls.models.Poll`` for this example.
     75The same ``closepoll`` could be easily modified to delete a given poll instead
     76of closing it by accepting additional command line options. These custom options
     77must be added to :attr:`~BaseCommand.option_list` like this:
     79.. code-block:: python
     81    from optparse import make_option
     83    class Command(BaseCommand):
     84        option_list = BaseCommand.option_list + (
     85                            make_option('--delete', action='store_true',
     86                                dest='delete',
     87                                default=False,
     88                                help='Delete poll instead of closing it'),
     89                          )
     90        # ...
     92In addition to being able to add custom command line options, all
     93:ref:`management commands<ref-django-admin>` can accept some
     94default options such as :djadminopt:`--verbosity` and :djadminopt:`--traceback`.
     96Command objects
     99.. class:: BaseCommand
     101The base class from which all management commands ultimately derive.
     103Use this class if you want access to all of the mechanisms which
     104parse the command-line arguments and work out what code to call in
     105response; if you don't need to change any of that behavior,
     106consider using one of its :ref:`subclasses<ref-basecommand-subclasses>`.
     108Subclassing the :class:`BaseCommand` class requires that you implement the
     109:meth:`~BaseCommand.handle` method.
     114All attributes can be set in your derived class and can be used in
     115:class:`BaseCommand`'s :ref:`subclasses<ref-basecommand-subclasses>`.
     117.. attribute:: BaseCommand.args
     119  A string listing the arguments accepted by the command,
     120  suitable for use in help messages; e.g., a command which takes
     121  a list of application names might set this to '<appname
     122  appname ...>'.
     124.. attribute:: BaseCommand.can_import_settings
     126  A boolean indicating whether the command needs to be able to
     127  import Django settings; if ``True``, ``execute()`` will verify
     128  that this is possible before proceeding. Default value is
     129  ``True``.
     131.. attribute:: BaseCommand.help
     133  A short description of the command, which will be printed in the
     134  help message when the user runs the command
     135  ``python manage.py help <command>``.
     137.. attribute:: BaseCommand.option_list
     139  This is the list of ``optparse`` options which will be fed
     140  into the command's ``OptionParser`` for parsing arguments.
     142.. attribute:: BaseCommand.output_transaction
     144  A boolean indicating whether the command outputs SQL
     145  statements; if ``True``, the output will automatically be
     146  wrapped with ``BEGIN;`` and ``COMMIT;``. Default value is
     147  ``False``.
     149.. attribute:: BaseCommand.requires_model_validation
     151  A boolean; if ``True``, validation of installed models will be
     152  performed prior to executing the command. Default value is
     153  ``True``. To validate an individual application's models
     154  rather than all applications' models, call
     155  :meth:`~BaseCommand.validate` from :meth:`~BaseCommand.handle`.
     160:class:`BaseCommand` has a few methods that can be overridden but only
     161the :meth:`~BaseCommand.handle` method must be implemented.
     163.. admonition:: Implementing a constructor in a subclass
     165  If you implement ``__init__`` in your subclass of :class:`BaseCommand`,
     166  you must call :class:`BaseCommand`'s ``__init__``.
     168  .. code-block:: python
     170    class Command(BaseCommand):
     171        def __init__(self):
     172            super(Command, self).__init__()
     173            # ...
     175.. method:: BaseCommand.get_version()
     177    Return the Django version, which should be correct for all
     178    built-in Django commands. User-supplied commands can
     179    override this method to return their own version.
     181.. method:: BaseCommand.execute(*args, **options)
     183    Try to execute this command, performing model validation if
     184    needed (as controlled by the attribute
     185    :attr:`requires_model_validation`). If the command raises a
     186    :class:`CommandError`, intercept it and print it sensibly to
     187    stderr.
     189.. method:: BaseCommand.handle(*args, **options)
     191    The actual logic of the command. Subclasses must implement this method.
     193.. _ref-basecommand-subclasses:
     195BaseCommand subclasses
     198.. class:: AppCommand
     200A management command which takes one or more installed application
     201names as arguments, and does something with each of them.
     203Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
     204:meth:`~AppCommand.handle_app`, which will be called once for each application.
     206.. method:: AppCommand.handle_app(app, **options)
     208    Perform the command's actions for ``app``, which will be the
     209    Python module corresponding to an application name given on
     210    the command line.
     212.. class:: LabelCommand
     214A management command which takes one or more arbitrary arguments
     215(labels) on the command line, and does something with each of
     218Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
     219:meth:`~LabelCommand.handle_label`, which will be called once for each label.
     221.. method:: LabelCommand.handle_label(label, **options)
     223    Perform the command's actions for ``label``, which will be the
     224    string as given on the command line.
     226.. class:: NoArgsCommand
     228A command which takes no arguments on the command line.
     230Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
     231:meth:`~NoArgsCommand.handle_noargs`; :meth:`~BaseCommand.handle` itself is
     232overridden to ensure no arguments are passed to the command.
     234.. method:: NoArgsCommand.handle_noargs(**options)
     236    Perform this command's actions
     238.. _ref-command-exceptions:
     240Command exceptions
     243.. class:: CommandError
     245Exception class indicating a problem while executing a management
     248If this exception is raised during the execution of a management
     249command, it will be caught and turned into a nicely-printed error
     250message to the appropriate output stream (i.e., stderr); as a
     251result, raising this exception (with a sensible description of the
     252error) is the preferred way to indicate that something has gone
     253wrong in the execution of a command.
Back to Top