可以在Django管理命令中创建子解析器吗? [英] Is it possible to create subparsers in a django management command?

查看:20
本文介绍了可以在Django管理命令中创建子解析器吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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值是您在用户指定foo子命令时决定subcommand选项应设置的值。我经常将其设置为Callable。

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的解析器属于同一类。碰巧您在parser中获得的解析器是一个CommandParser实例(在django.core.management.base中定义)。CommandParser**kwargs之前需要cmd参数(而argparse提供的默认解析器类只接受**kwargs):

def __init__(self, cmd, **kwargs):

因此,当您尝试添加子解析器时,它会失败,因为仅使用**kwargs调用构造函数,并且缺少cmd参数。

上面的代码通过传入parser_class参数来修复此问题。

添加缺少的参数的类。

注意事项:

  1. 在上面的代码中,我创建了一个新类,因为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))
    
    目前我还没有遇到任何问题,但未来对argparse的更改可能会导致使用lambda而不是真正的类失败。由于该参数名为parser_class,而不是parser_makerparser_manufacture,我认为这样的更改是公平的。

    /li>
  2. 难道我们不能只传递一个常用的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管理命令中创建子解析器吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆