django - 是否可以在 django 管理命令中创建子解析器?

标签 django argparse django-manage.py subparsers

标题确实说明了一切,但我目前有这个,但它不起作用:

class Command(BaseCommand):
    help = ("Functions related to downloading, parsing, and indexing the  "
            "content")

    def add_arguments(self, parser):
        subparsers = parser.add_subparsers()

        download_parser = subparsers.add_parser(
            'download',
            help='Using a local CSV, download the XML data for content. '
                 'Output is sent to the log.'
        )
        download_parser.add_argument(
            '--start_line',
            type=int,
            default=0,
            help='The line in the file where you wish to start processing.'
        )

        # Add an argparse parser for parsing the content. Yes, this is
        # a bit confusing.
        content_parser_parser = subparsers.add_parser(
            'parse',
            help="Look at the file system and parse everything you see so that "
                 "we have content in the databse."
        )
        content_parser_parser.add_argument(
            '--start_item',
            type=int,
            default=0,
            help="Assuming the content is sorted by file name, this item is "
                 "the one to start on."
        )

我的具体想法是创建一个具有子命令的命令,用于下载 XML 内容或将其解析到数据库中。

最佳答案

Django 2.1 及更高版本

在 Django 2.1 及更高版本中,添加子命令很简单:

from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def add_arguments(self, parser):
        subparsers = parser.add_subparsers(title="subcommands",
                                           dest="subcommand",
                                           required=True)

然后你使用 subparser如果你正在编写一个使用 argparse 的非 Django 应用程序,你会这样做。 .例如,如果您想要一个名为 foo 的子命令这可能需要--bar争论:
foo = subparsers.add_parser("foo")
foo.set_defaults(subcommand=fooVal)
foo.add_argument("--bar")

fooVal是你决定的subcommand当用户指定 foo 时,选项应设置为子命令。我经常将它设置为可调用的。

旧版本的 Django

这是可能的,但需要一些工作:
from django.core.management.base import BaseCommand, CommandParser

class Command(BaseCommand):

    [...]

    def add_arguments(self, parser):
        cmd = self

        class SubParser(CommandParser):

            def __init__(self, **kwargs):
                super(SubParser, self).__init__(cmd, **kwargs)

        subparsers = parser.add_subparsers(title="subcommands",
                                           dest="subcommand",
                                           required=True,
                                           parser_class=SubParser)

当您调用 add_subparsers默认 argparse创建一个与调用 add_subparser 的解析器属于同一类的新解析器.碰巧你得到的解析器 parserCommandParser实例(在 django.core.management.base 中定义)。 CommandParser类(class) 需要 一个 cmd **kwargs 之前的参数(而 argparse 提供的默认解析器类只需要 **kwargs ):
def __init__(self, cmd, **kwargs):

因此,当您尝试添加子解析器时,它会失败,因为仅使用 **kwargs 调用构造函数和 cmd论据不见了。

上面的代码通过传入 parser_class 解决了这个问题。 argument 一个添加缺失参数的类。

需要考虑的事项:
  • 在上面的代码中,我创建了一个新类,因为名称 parser_class表明应该在那里传递的是一个真正的类。但是,这也有效:
    def add_arguments(self, parser):
        cmd = self
        subparsers = parser.add_subparsers(
            title="subcommands",
            dest="subcommand",
            required=True,
            parser_class=lambda **kw: CommandParser(cmd, **kw))
    

    现在我没有遇到任何问题,但 future 可能会更改为 argparse可能会使使用 lambda 而不是真正的类失败。由于参数被称为 parser_class而不是 parser_makerparser_manufacture我认为这样的改变是公平的游戏。
  • 我们不能只通过一只股票argparse类而不是在 parser_class 中传递自定义类?不会有直接的问题,但会产生意想不到的后果。 CommandParser 中的评论表明 argparse 的行为的棒解析器不适用于 Django 命令。特别是 docstring对于类状态:
    """
    Customized ArgumentParser class to improve some error messages and prevent
    SystemExit in several occasions, as SystemExit is unacceptable when a
    command is called programmatically.
    """
    

    这是 Jerzyk's answer 的问题患有。此处的解决方案通过派生 CommandParser 来避免该问题。从而提供 Django 所需的正确行为。
  • 关于django - 是否可以在 django 管理命令中创建子解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36706220/

    相关文章:

    django - 如何在Django中输入完整的历史记录?

    python - Django:返回渲染可哈希错误

    python - 如何使用 `argparse` 从命令行和代码传递参数?

    python - Django:通过manage.py使用服务器和gunicorn等其他服务器之间的区别。哪个更好?

    python - django 托管错误,关于alwaysdata.com

    python - Django,如何按日期对模型进行分组?

    python - argparse 中的交叉参数验证

    python - 类型错误 : __init__() got an unexpected keyword argument 'type' (argparse issue? )

    Django管理命令: using LabelCommand

    django - 除了命令之外,Django 中的管理文件夹还有其他用途吗?