标题真的说明了一切,但我现在有这个,但它不起作用:
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内容或将其解析为数据库的子命令。
答案 0 :(得分:9)
在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
选项设置为的任何值。我经常将它设置为可调用。
这是可能的,但需要一些工作:
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
之前,cmd
类需要 **kwargs
参数(而argparse
提供的默认解析器类只需要**kwargs
) :
def __init__(self, cmd, **kwargs):
因此,当您尝试添加subparser时,它会失败,因为仅使用**kwargs
调用构造函数并且缺少cmd
参数。
上面的代码通过向parser_class
参数传递一个添加缺少参数的类来解决问题。
需要考虑的事项:
在上面的代码中,我创建了一个新类,因为名称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_maker
或parser_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所需的正确行为。
答案 1 :(得分:2)
你可以添加它,这非常简单:
class Command(BaseCommand):
help = 'dump/restore/diff'
def add_arguments(self, parser):
parser.add_argument('-s', '--server', metavar='server', type=str,
help='server address')
parser.add_argument('-d', '--debug', help='Print lots of debugging')
subparsers = parser.add_subparsers(metavar='command',
dest='command',
help='sub-command help')
subparsers.required = True
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('machine', metavar='device', type=str)
parent_parser.add_argument('-e', '--errors', action='store_true')
parser_dump = subparsers.add_parser('dump', parents=[parent_parser],
cmd=self)
parser_dump.add_argument('-i', '--indent', metavar='indent', type=int,
default=None, help='file indentation')
parser_restore = subparsers.add_parser('restore',
parents=[parent_parser],
cmd=self)
parser_restore.add_argument('infile', nargs='?',
type=argparse.FileType('r'),
default=sys.stdin)
parser_diff = subparsers.add_parser('diff', parents=[parent_parser],
cmd=self)
parser_diff.add_argument('infile', nargs='?',
type=argparse.FileType('r'),
default=sys.stdin)