Django实践:自定义管理命令

99 阅读3分钟

如何自定义管理命令

在通过上篇文章《Django源码解析之CLI模块解析》, 明白了Django是如何解析并执行命令行之后, 接下来让我们尝试编写一个自己的管理命令。

步骤一

首先, 需要在 DjangoApp 下创建目录<django_app_path>/management/commands, Django检索管理命令是以 App 为单位检索的。样例的目录结构如下所示:

.
├── custom_cli
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── management
│   │   ├── __init__.py
│   │   └── commands
│   │       ├── __init__.py

步骤二

<django_app_path>/management/commands路径下新建一个<cli_name>.py文件, 该文件的文件名就是管理命令的名称了。

  • 在本次示例中, 新建一个名为custom_test_cli.py的文件。

步骤三

编辑步骤二新建的文件, 在内部新建一个名为Command并且继承自django.core.management.BaseCommand的类。 到这一步时, 已经可以通过python manage.py help命令看到我们自定义的管理命令了。

查看管理命令

需要注意的是类名必须是Command, 否则在执行时将会得到一个 AttributeError 的异常。

AttributeError异常

然后重写Command类的add_arguments方法, 为该管理命令增加自己的所需的参数。

class Command(BaseCommand):
    default_name = "永夜旅人"

    def add_arguments(self, parser: django.core.management.CommandParser):
        """
        该 hook 用于添加所需的参数,
        会在调用 self.create_parser() 的最后调用该 hook, 用于添加我们自定义的参数列表
        :param parser: 通过 create_parser 创建的参数解析器
        """
        parser.add_argument("--who", "-w", default=self.default_name,
                            help="告诉管理命令需要输出谁的名字")

完成add_arguments方法的重写后, 可以通过python manage.py help <custom_cli_name>来查看效果。 自定义管理命令的help

最后, 通过实现handle方法来决定该管理命令的运行逻辑。

    def handle(self, *args, **options):
        # 向 stdout 中写入指定信息
        self.stdout.write(f"hello {options['who']}, welcome to use demo management command")

来看一下执行的效果。 不带参数运行 带参数运行

额外说明

除了BaseCommand之外, Django 还提供了下面2种基类(都是BaseCommand的子类)供开发者使用。

  • LabelCommand:
    • 入参中所有的 arguments 都当作是一个 label, 对每一个 label 进行批量处理。
    • 必须实现handle_label方法。
  • AppCommand:
    • 可以算是 LabelCommand 的一个子类, 入参中所有的 arguments 都算一个 DjangoAppName, 可以实现对指定的 app 列表进行批量处理的操作。
    • 如果入参的 app_name 无效, 则会抛出CommandError的异常。
    • 必须实现handle_app_config方法。

下面是一些BaseCommand内部属性的说明

  • help: String 类型,用来指定带-h参数执行时的输出内容, 相当于是该管理命令的说明。
  • requires_system_checks: list 类型, 说明该管理命令在执行前是否需要进行系统检查。 默认为[__all__], 表示需要进行全部的系统检查, 支持的元素类型为django.core.checks.registry.Tags
  • requires_migrations_checks: boolean 类型, 默认为False, 该属性为True时, 在执行管理命令前会检查migrations中的表结构是否与数据库的一致, 如果不一致则会输出 warning.
  • output_transaction: boolean 类型, 默认为False, 该属性为True时, 会将管理命令的执行结果用 BEGIN;COMMIT; 包围后然后输出。 像下面这样, 这在用管理命令生成SQL语句时是非常有用的:
BEGIN;
-- 这里是管理命令的输出
select * from table;
COMMIT;