summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2014-06-06 17:55:56 +0200
committerClaude Paroz <claude@2xlibre.net>2014-06-14 13:42:43 +0200
commitcbff097bd91fad42c7231026968f686598b1d7a2 (patch)
tree9d43856125c7dd10a6077642d413bed134a8506e /docs
parent856863860352aa1f0288e6c9168a0e423c4f5184 (diff)
Documented optparse to argparse changes for management commands
Diffstat (limited to 'docs')
-rw-r--r--docs/howto/custom-management-commands.txt79
-rw-r--r--docs/internals/deprecation.txt3
-rw-r--r--docs/releases/1.8.txt25
3 files changed, 93 insertions, 14 deletions
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index bbbd31af6c..bb15597a34 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -50,13 +50,15 @@ look like this:
from polls.models import Poll
class Command(BaseCommand):
- args = '<poll_id poll_id ...>'
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):
- for poll_id in args:
+ for poll_id in options['poll_id']:
try:
- poll = Poll.objects.get(pk=int(poll_id))
+ poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
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)
+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:
.. note::
@@ -81,28 +91,34 @@ look like this:
The new custom command can be called using ``python manage.py closepoll
<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
:class:`CommandError` is raised. The ``poll.opened`` attribute does not exist
in the :doc:`tutorial</intro/tutorial01>` and was added to
``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
-of closing it by accepting additional command line options. These custom options
-must be added to :attr:`~BaseCommand.option_list` like this:
+of closing it by accepting additional command line options. These custom
+options can be added in the :meth:`~BaseCommand.add_arguments` method like this:
.. code-block:: python
- from optparse import make_option
-
class Command(BaseCommand):
- option_list = BaseCommand.option_list + (
- make_option('--delete',
+ def add_arguments(self, parser):
+ # Positional arguments
+ parser.add_argument('poll_id', nargs='+', type=int)
+
+ # Named (optional) arguments
+ parser.add_argument('--delete',
action='store_true',
dest='delete',
default=False,
- help='Delete poll instead of closing it'),
- )
+ help='Delete poll instead of closing it')
def handle(self, *args, **options):
# ...
@@ -110,9 +126,15 @@ must be added to :attr:`~BaseCommand.option_list` like this:
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
-parameter of the handle method. See the :py:mod:`optparse` Python documentation
-for more about ``make_option`` usage.
+parameter of the handle method. See the :py:mod:`argparse` Python documentation
+for more about ``add_argument`` usage.
In addition to being able to add custom command line options, all
: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
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
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
``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
This is the list of ``optparse`` options which will be fed
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
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)
# ...
+.. 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()
Return the Django version, which should be correct for all
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 3cbd1e3173..82ffe4938f 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -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
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:
1.9
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index f4098fa08a..437c27189f 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -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.
+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
~~~~~~~~~~~~~
@@ -409,3 +423,14 @@ Similarly for GIS sitemaps, add ``name='django.contrib.gis.sitemaps.views.kml'``
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
+
+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.