diff -r 5ff1fc726848 -r c6bca38c1cbf parts/django/docs/howto/custom-management-commands.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parts/django/docs/howto/custom-management-commands.txt Sat Jan 08 11:20:57 2011 +0530 @@ -0,0 +1,253 @@ +==================================== +Writing custom django-admin commands +==================================== + +.. versionadded:: 1.0 + +Applications can register their own actions with ``manage.py``. For example, +you might want to add a ``manage.py`` action for a Django app that you're +distributing. In this document, we will be building a custom ``closepoll`` +command for the ``polls`` application from the +:doc:`tutorial`. + +To do this, just add a ``management/commands`` directory to the application. +Each Python module in that directory will be auto-discovered and registered as +a command that can be executed as an action when you run ``manage.py``:: + + polls/ + __init__.py + models.py + management/ + __init__.py + commands/ + __init__.py + closepoll.py + tests.py + views.py + +In this example, the ``closepoll`` command will be made available to any project +that includes the ``polls`` application in :setting:`INSTALLED_APPS`. + +The ``closepoll.py`` module has only one requirement -- it must define a class +``Command`` that extends :class:`BaseCommand` or one of its +:ref:`subclasses`. + +.. admonition:: Standalone scripts + + Custom management commands are especially useful for running standalone + scripts or for scripts that are periodically executed from the UNIX crontab + or from Windows scheduled tasks control panel. + +To implement the command, edit ``polls/management/commands/closepoll.py`` to +look like this: + +.. code-block:: python + + from django.core.management.base import BaseCommand, CommandError + from example.polls.models import Poll + + class Command(BaseCommand): + args = '' + 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() + + print 'Successfully closed poll "%s"' % poll_id + +The new custom command can be called using ``python manage.py closepoll +``. + +The ``handle()`` method takes zero or more ``poll_ids`` and sets ``poll.opened`` +to ``False`` for each one. If the user referenced any nonexistant polls, a +:class:`CommandError` is raised. The ``poll.opened`` attribute does not exist +in the :doc:`tutorial` and was added to +``polls.models.Poll`` for this example. + +The same ``closepoll`` could be easily modified to delete a given poll instead +of closing it by accepting additional command line options. These custom options +must be added to :attr:`~BaseCommand.option_list` like this: + +.. code-block:: python + + 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'), + ) + # ... + +In addition to being able to add custom command line options, all +:doc:`management commands` can accept some +default options such as :djadminopt:`--verbosity` and :djadminopt:`--traceback`. + +Command objects +=============== + +.. class:: BaseCommand + +The base class from which all management commands ultimately derive. + +Use this class if you want access to all of the mechanisms which +parse the command-line arguments and work out what code to call in +response; if you don't need to change any of that behavior, +consider using one of its :ref:`subclasses`. + +Subclassing the :class:`BaseCommand` class requires that you implement the +:meth:`~BaseCommand.handle` method. + +Attributes +---------- + +All attributes can be set in your derived class and can be used in +:class:`BaseCommand`'s :ref:`subclasses`. + +.. attribute:: BaseCommand.args + + A string listing the arguments accepted by the command, + suitable for use in help messages; e.g., a command which takes + a list of application names might set this to ''. + +.. attribute:: BaseCommand.can_import_settings + + A boolean indicating whether the command needs to be able to + import Django settings; if ``True``, ``execute()`` will verify + that this is possible before proceeding. Default value is + ``True``. + +.. attribute:: BaseCommand.help + + A short description of the command, which will be printed in the + help message when the user runs the command + ``python manage.py help ``. + +.. attribute:: BaseCommand.option_list + + This is the list of ``optparse`` options which will be fed + into the command's ``OptionParser`` for parsing arguments. + +.. attribute:: BaseCommand.output_transaction + + A boolean indicating whether the command outputs SQL + statements; if ``True``, the output will automatically be + wrapped with ``BEGIN;`` and ``COMMIT;``. Default value is + ``False``. + +.. attribute:: BaseCommand.requires_model_validation + + A boolean; if ``True``, validation of installed models will be + performed prior to executing the command. Default value is + ``True``. To validate an individual application's models + rather than all applications' models, call + :meth:`~BaseCommand.validate` from :meth:`~BaseCommand.handle`. + +Methods +------- + +:class:`BaseCommand` has a few methods that can be overridden but only +the :meth:`~BaseCommand.handle` method must be implemented. + +.. admonition:: Implementing a constructor in a subclass + + If you implement ``__init__`` in your subclass of :class:`BaseCommand`, + you must call :class:`BaseCommand`'s ``__init__``. + + .. code-block:: python + + class Command(BaseCommand): + def __init__(self, *args, **kwargs): + super(Command, self).__init__(*args, **kwargs) + # ... + +.. method:: BaseCommand.get_version() + + Return the Django version, which should be correct for all + built-in Django commands. User-supplied commands can + override this method to return their own version. + +.. method:: BaseCommand.execute(*args, **options) + + Try to execute this command, performing model validation if + needed (as controlled by the attribute + :attr:`requires_model_validation`). If the command raises a + :class:`CommandError`, intercept it and print it sensibly to + stderr. + +.. method:: BaseCommand.handle(*args, **options) + + The actual logic of the command. Subclasses must implement this method. + +.. _ref-basecommand-subclasses: + +BaseCommand subclasses +---------------------- + +.. class:: AppCommand + +A management command which takes one or more installed application +names as arguments, and does something with each of them. + +Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement +:meth:`~AppCommand.handle_app`, which will be called once for each application. + +.. method:: AppCommand.handle_app(app, **options) + + Perform the command's actions for ``app``, which will be the + Python module corresponding to an application name given on + the command line. + +.. class:: LabelCommand + +A management command which takes one or more arbitrary arguments +(labels) on the command line, and does something with each of +them. + +Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement +:meth:`~LabelCommand.handle_label`, which will be called once for each label. + +.. method:: LabelCommand.handle_label(label, **options) + + Perform the command's actions for ``label``, which will be the + string as given on the command line. + +.. class:: NoArgsCommand + +A command which takes no arguments on the command line. + +Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement +:meth:`~NoArgsCommand.handle_noargs`; :meth:`~BaseCommand.handle` itself is +overridden to ensure no arguments are passed to the command. + +.. method:: NoArgsCommand.handle_noargs(**options) + + Perform this command's actions + +.. _ref-command-exceptions: + +Command exceptions +------------------ + +.. class:: CommandError + +Exception class indicating a problem while executing a management +command. + +If this exception is raised during the execution of a management +command, it will be caught and turned into a nicely-printed error +message to the appropriate output stream (i.e., stderr); as a +result, raising this exception (with a sensible description of the +error) is the preferred way to indicate that something has gone +wrong in the execution of a command.