Documented optparse to argparse changes for management commands
This commit is contained in:
parent
8568638603
commit
cbff097bd9
|
@ -50,13 +50,15 @@ look like this:
|
||||||
from polls.models import Poll
|
from polls.models import Poll
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
args = '<poll_id poll_id ...>'
|
|
||||||
help = 'Closes the specified poll for voting'
|
help = 'Closes the specified poll for voting'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('poll_id', nargs='+', type=int)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
for poll_id in args:
|
for poll_id in options['poll_id']:
|
||||||
try:
|
try:
|
||||||
poll = Poll.objects.get(pk=int(poll_id))
|
poll = Poll.objects.get(pk=poll_id)
|
||||||
except Poll.DoesNotExist:
|
except Poll.DoesNotExist:
|
||||||
raise CommandError('Poll "%s" does not exist' % poll_id)
|
raise CommandError('Poll "%s" does not exist' % poll_id)
|
||||||
|
|
||||||
|
@ -65,6 +67,14 @@ look like this:
|
||||||
|
|
||||||
self.stdout.write('Successfully closed poll "%s"' % poll_id)
|
self.stdout.write('Successfully closed poll "%s"' % poll_id)
|
||||||
|
|
||||||
|
Before Django 1.8, management commands were based on the :py:mod:`optparse`
|
||||||
|
module, and positional arguments were passed in ``*args`` while optional
|
||||||
|
arguments were passed in ``**options``. Now that management commands use
|
||||||
|
:py:mod:`argparse` for argument parsing, all arguments are passed in
|
||||||
|
``**options`` by default, unless you name your positional arguments to ``args``
|
||||||
|
(compatibility mode). You are encouraged to exclusively use ``**options`` for
|
||||||
|
new commands.
|
||||||
|
|
||||||
.. _management-commands-output:
|
.. _management-commands-output:
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -81,28 +91,34 @@ look like this:
|
||||||
The new custom command can be called using ``python manage.py closepoll
|
The new custom command can be called using ``python manage.py closepoll
|
||||||
<poll_id>``.
|
<poll_id>``.
|
||||||
|
|
||||||
The ``handle()`` method takes zero or more ``poll_ids`` and sets ``poll.opened``
|
The ``handle()`` method takes one or more ``poll_ids`` and sets ``poll.opened``
|
||||||
to ``False`` for each one. If the user referenced any nonexistent polls, a
|
to ``False`` for each one. If the user referenced any nonexistent polls, a
|
||||||
:class:`CommandError` is raised. The ``poll.opened`` attribute does not exist
|
:class:`CommandError` is raised. The ``poll.opened`` attribute does not exist
|
||||||
in the :doc:`tutorial</intro/tutorial01>` and was added to
|
in the :doc:`tutorial</intro/tutorial01>` and was added to
|
||||||
``polls.models.Poll`` for this example.
|
``polls.models.Poll`` for this example.
|
||||||
|
|
||||||
|
.. _custom-commands-options:
|
||||||
|
|
||||||
|
Accepting optional arguments
|
||||||
|
============================
|
||||||
|
|
||||||
The same ``closepoll`` could be easily modified to delete a given poll instead
|
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
|
of closing it by accepting additional command line options. These custom
|
||||||
must be added to :attr:`~BaseCommand.option_list` like this:
|
options can be added in the :meth:`~BaseCommand.add_arguments` method like this:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from optparse import make_option
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
option_list = BaseCommand.option_list + (
|
def add_arguments(self, parser):
|
||||||
make_option('--delete',
|
# Positional arguments
|
||||||
|
parser.add_argument('poll_id', nargs='+', type=int)
|
||||||
|
|
||||||
|
# Named (optional) arguments
|
||||||
|
parser.add_argument('--delete',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
dest='delete',
|
dest='delete',
|
||||||
default=False,
|
default=False,
|
||||||
help='Delete poll instead of closing it'),
|
help='Delete poll instead of closing it')
|
||||||
)
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
# ...
|
# ...
|
||||||
|
@ -110,9 +126,15 @@ must be added to :attr:`~BaseCommand.option_list` like this:
|
||||||
poll.delete()
|
poll.delete()
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
|
.. versionchanged:: 1.8
|
||||||
|
|
||||||
|
Previously, only the standard :py:mod:`optparse` library was supported and
|
||||||
|
you would have to extend the command ``option_list`` variable with
|
||||||
|
``optparse.make_option()``.
|
||||||
|
|
||||||
The option (``delete`` in our example) is available in the options dict
|
The option (``delete`` in our example) is available in the options dict
|
||||||
parameter of the handle method. See the :py:mod:`optparse` Python documentation
|
parameter of the handle method. See the :py:mod:`argparse` Python documentation
|
||||||
for more about ``make_option`` usage.
|
for more about ``add_argument`` usage.
|
||||||
|
|
||||||
In addition to being able to add custom command line options, all
|
In addition to being able to add custom command line options, all
|
||||||
:doc:`management commands</ref/django-admin>` can accept some
|
:doc:`management commands</ref/django-admin>` can accept some
|
||||||
|
@ -202,6 +224,12 @@ All attributes can be set in your derived class and can be used in
|
||||||
a list of application names might set this to '<app_label
|
a list of application names might set this to '<app_label
|
||||||
app_label ...>'.
|
app_label ...>'.
|
||||||
|
|
||||||
|
.. deprecated:: 1.8
|
||||||
|
|
||||||
|
This should be done now in the :meth:`~BaseCommand.add_arguments()`
|
||||||
|
method, by calling the ``parser.add_argument()`` method. See the
|
||||||
|
``closepoll`` example above.
|
||||||
|
|
||||||
.. attribute:: BaseCommand.can_import_settings
|
.. attribute:: BaseCommand.can_import_settings
|
||||||
|
|
||||||
A boolean indicating whether the command needs to be able to
|
A boolean indicating whether the command needs to be able to
|
||||||
|
@ -215,11 +243,25 @@ All attributes can be set in your derived class and can be used in
|
||||||
help message when the user runs the command
|
help message when the user runs the command
|
||||||
``python manage.py help <command>``.
|
``python manage.py help <command>``.
|
||||||
|
|
||||||
|
.. attribute:: BaseCommand.missing_args_message
|
||||||
|
|
||||||
|
.. versionadded:: 1.8
|
||||||
|
|
||||||
|
If your command defines mandatory positional arguments, you can customize
|
||||||
|
the message error returned in the case of missing arguments. The default is
|
||||||
|
output by :py:mod:`argparse` ("too few arguments").
|
||||||
|
|
||||||
.. attribute:: BaseCommand.option_list
|
.. attribute:: BaseCommand.option_list
|
||||||
|
|
||||||
This is the list of ``optparse`` options which will be fed
|
This is the list of ``optparse`` options which will be fed
|
||||||
into the command's ``OptionParser`` for parsing arguments.
|
into the command's ``OptionParser`` for parsing arguments.
|
||||||
|
|
||||||
|
.. deprecated:: 1.8
|
||||||
|
|
||||||
|
You should now override the :meth:`~BaseCommand.add_arguments` method to
|
||||||
|
add custom arguments accepted by your command.
|
||||||
|
See :ref:`the example above <custom-commands-options>`.
|
||||||
|
|
||||||
.. attribute:: BaseCommand.output_transaction
|
.. attribute:: BaseCommand.output_transaction
|
||||||
|
|
||||||
A boolean indicating whether the command outputs SQL
|
A boolean indicating whether the command outputs SQL
|
||||||
|
@ -287,6 +329,15 @@ the :meth:`~BaseCommand.handle` method must be implemented.
|
||||||
super(Command, self).__init__(*args, **kwargs)
|
super(Command, self).__init__(*args, **kwargs)
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
|
.. method:: BaseCommand.add_arguments(parser)
|
||||||
|
|
||||||
|
.. versionadded:: 1.8
|
||||||
|
|
||||||
|
Entry point to add parser arguments to handle command line arguments passed
|
||||||
|
to the command. Custom commands should override this method to add both
|
||||||
|
positional and optional arguments accepted by the command. Calling
|
||||||
|
``super()`` is not needed when directly subclassing ``BaseCommand``.
|
||||||
|
|
||||||
.. method:: BaseCommand.get_version()
|
.. method:: BaseCommand.get_version()
|
||||||
|
|
||||||
Return the Django version, which should be correct for all
|
Return the Django version, which should be correct for all
|
||||||
|
|
|
@ -35,6 +35,9 @@ about each item can often be found in the release notes of two versions prior.
|
||||||
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
* The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
|
||||||
Python path will be removed.
|
Python path will be removed.
|
||||||
|
|
||||||
|
* Support for :py:mod:`optparse` will be dropped for custom management commands
|
||||||
|
(replaced by :py:mod:`argparse`).
|
||||||
|
|
||||||
.. _deprecation-removed-in-1.9:
|
.. _deprecation-removed-in-1.9:
|
||||||
|
|
||||||
1.9
|
1.9
|
||||||
|
|
|
@ -280,6 +280,20 @@ Now, an error will be raised to prevent data loss::
|
||||||
...
|
...
|
||||||
ValueError: Cannot assign "<Author: John>": "Author" instance isn't saved in the database.
|
ValueError: Cannot assign "<Author: John>": "Author" instance isn't saved in the database.
|
||||||
|
|
||||||
|
Management commands that only accept positional arguments
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you have written a custom management command that only accepts positional
|
||||||
|
arguments and you didn't specify the
|
||||||
|
:attr:`~django.core.management.BaseCommand.args` command variable, you might
|
||||||
|
get an error like ``Error: unrecognized arguments: ...``, as variable parsing
|
||||||
|
is now based on :py:mod:`argparse` which doesn't implicitly accept positional
|
||||||
|
arguments. You can make your command backwards compatible by simply setting the
|
||||||
|
:attr:`~django.core.management.BaseCommand.args` class variable. However, if
|
||||||
|
you don't have to keep compatibility with older Django versions, it's better to
|
||||||
|
implement the new :meth:`~django.core.management.BaseCommand.add_arguments`
|
||||||
|
method as described in :doc:`/howto/custom-management-commands`.
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -409,3 +423,14 @@ Similarly for GIS sitemaps, add ``name='django.contrib.gis.sitemaps.views.kml'``
|
||||||
or ``name='django.contrib.gis.sitemaps.views.kmz'``.
|
or ``name='django.contrib.gis.sitemaps.views.kmz'``.
|
||||||
|
|
||||||
.. _security issue: https://www.djangoproject.com/weblog/2014/apr/21/security/#s-issue-unexpected-code-execution-using-reverse
|
.. _security issue: https://www.djangoproject.com/weblog/2014/apr/21/security/#s-issue-unexpected-code-execution-using-reverse
|
||||||
|
|
||||||
|
Extending management command arguments through ``Command.option_list``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Management commands now use :py:mod:`argparse` instead of :py:mod:`optparse` to
|
||||||
|
parse command-line arguments passed to commands. This also means that the way
|
||||||
|
to add custom arguments to commands has changed: instead of extending the
|
||||||
|
``option_list`` class list, you should now override the
|
||||||
|
:meth:`~django.core.management.BaseCommand.add_arguments` method and add
|
||||||
|
arguments through ``argparse.add_argument()``. See
|
||||||
|
:ref:`this example <custom-commands-options>` for more details.
|
||||||
|
|
Loading…
Reference in New Issue