3

The signature of BaseCommand.handle is handle(*args, **kwargs). The documentation example only uses the kwargs argument.

Are there cases/ways to define command arguments/options such that they will appear as positional arguments to the handle function?

1
  • For positional and named parameters. Commented Jan 14, 2022 at 22:47

2 Answers 2

1

To answer: "What is *args in a Django BaseCommand handle function for?"...

The *args is a way to define the arguments of the handle(...) method.

As far as I can tell, in the BaseCommand.handle(...), args is not connected to command line argument parsing in any way.

As an aside, using * and ** is common practice in Python when you don't know how many arguments will be passed to the method. The names (e.g. args, kwargs, options are determined by the author of the code, and can be anything.

If you want to learn more about * and ** in Python, some places to start:

To answer: "Are there cases/ways to define command arguments/options such that they will appear as positional arguments to the handle function?"...

As far as I can tell, no. Assuming you use the add_arguments(...) method, arguments from the command line will always get placed in the options dict.

To answer a question that wasn't asked, but maybe will be useful to readers: How can you get a required positional argument in the handle(...) method?

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('required_arg')
        parser.add_argument('-o', '--optional_arg')
    
    def handle(self, *args, **options):
        print(f"req: '{options['required_arg']}'; opt: '{options['optional_arg']}'")
python manage.py foo
manage.py foo: error: the following arguments are required: required_arg

python manage.py foo hello
req: 'hello'; opt: 'None'

python manage.py foo hello -o world
req: 'hello'; opt: 'world'

Sign up to request clarification or add additional context in comments.

Comments

1

I've always been curious about this too, but I've never paid much attention to it until now, when I came across your question and decided to take a closer look. Upon inspecting the code, I discovered that the *args parameter in BaseCommand.handle serves only one purpose: if you define an argument with the name 'args', it will appear in args instead of options. For example, if I define a class like this:

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('args', type=str, nargs='+', default=None)
        parser.add_argument('-f', type=str)

    def handle(self, *args, **options):
        print(args)
        print(options)

Then when I call it like this:

python manage.py mycommand foo bar -f whatever

It'll print:

('foo', 'bar')
{'f': 'whatever', 'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False, 'no_color': False, 'force_color': False, 'skip_checks': False}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.