Mohammad Adnan
Mohammad Adnan

Reputation: 41

How can i implement app namespace in django commands?

I want to implement django app namespacing in commands like

python manage.py appname:command --parameters

and

python manage.py appname:command:subcommand --parameters

how I can do this ?

Upvotes: 4

Views: 441

Answers (1)

illagrenan
illagrenan

Reputation: 6555

Django management commands are based on argparse (since Django 1.10 [1]) from the Python standard library. One possible solution is to use subparser. [2]

First create a file as a standard management command, e.g.: yourapp/management/commands/base.py.

from __future__ import annotations

from typing import Any, Callable, Dict

from django.core.management.base import BaseCommand


def create_resource(**options):
    print("Creating resource %s" % options["name_of_resource_to_create"])


def delete_resource(**options):
    print("Deleting resource %s" % options["name_of_resource_to_delete"])


SUBCOMMANDS_MAPPING: Dict[str, Callable[[Dict[str, Any]], None]] = {
    "create_resource": create_resource,
    "delete_resource": delete_resource,
}


class Command(BaseCommand):
    def add_arguments(self, parser):
        subparsers = parser.add_subparsers(
            dest="subcommand",
            title="positional arguments:",
            description="Required positional arguments to specify subcommand to execute.",
            required=True,
        )

        # Parser for create_resource:
        parser_serve = subparsers.add_parser(name="create_resource")
        parser_serve.add_argument("name_of_resource_to_create", type=str)

        # Parser for delete_resource:
        parser_serve = subparsers.add_parser(name="delete_resource")
        parser_serve.add_argument("name_of_resource_to_delete", type=str)

    def handle(self, *args, **options):
        print('Base command')
        SUBCOMMANDS_MAPPING[options.pop("subcommand")](**options)

We added a subparser called subcommand. Each subcommand has its own separate required/optional arguments. The subcommand name will be contained in the subcommand key. Based on this value, we decide which function to run.

This is what the help output looks like:

$ python manage.py base --help

usage: manage.py base [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks] {create_resource,delete_resource} ...

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -v {0,1,2,3}, --verbosity {0,1,2,3}
                        Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output
  --settings SETTINGS   The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used.
  --pythonpath PYTHONPATH
                        A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".
  --traceback           Raise on CommandError exceptions
  --no-color            Don't colorize the command output.
  --force-color         Force colorization of the command output.
  --skip-checks         Skip system checks.

positional arguments::
  Required positional arguments to specify subcommand to execute.

  {create_resource,delete_resource}


$ python manage.py create_resource --help

usage: manage.py base create_resource [-h] name_of_resource_to_create

positional arguments:
  name_of_resource_to_create

optional arguments:
  -h, --help            show this help message and exit

I tested this solution in Django 3.1 and Python 3.9. The source of inspiration for me was this answer: https://stackoverflow.com/a/37414551/752142.

Upvotes: 1

Related Questions