2016-04-18 16 views
5

タイトルは実際にそれをすべて言うが、私は現在、これを持っているが、それは動作しません: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コンテンツをダウンロードするか、データベースにそれを解析するためのサブコマンドがあり一つのコマンドを作成することです。

+0

すでに 'parser'にあるもの知らず、あるいはどのような' django'、後でそれでそれをしない、私が言うことができません。あなたのサブパーザの定義はうまくいきます。しかし、他のSOの質問から分かるように、サブパーザを他の引数、位置および/またはオプションで使用することは難しい可能性があります。診断のように、関数の先頭に 'print parser._actions'を追加してください。 – hpaulj

+0

http://stackoverflow.com/questions/31919101/djangos-call-command-fails-with-missing-required-argumentsは、argparseとdjangoの両方に関係する以前の質問の1つです。 djangoはoptparseの使用に似ていますが、最近argparseの代替が追加されました。 – hpaulj

答えて

7

ことは可能であるが、それは仕事のビットを必要とします。

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", 
              parser_class=SubParser) 

デフォルト​​でadd_subparsersを呼び出すときは、あなたがadd_subparserと呼ばれているパーザと同じクラスである新しいパーサを作成します。 parserにあるパーサは、CommandParserインスタンス(django.core.management.baseで定義されています)になります。だから、

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

あなたがsubparserを追加しようとすると、コンストラクタにのみ呼び出されるため、それが失敗し、:(​​によって提供されるデフォルトのパーサークラスのみ**kwargsを取るのに対し)CommandParserクラス**kwargscmd引数が必要**kwargsで、cmd引数がありません。

上記のコードでは、欠落しているパラメータを追加するクラスにparser_class引数を渡して問題を解決しています。考慮すべき

物事:名前parser_classが渡されるべき実際のクラスがあることを示唆しているので、上記のコードで

  1. は、私は新しいクラスを作成します。しかし、これも動作します:

    def add_arguments(self, parser): 
        cmd = self 
        subparsers = parser.add_subparsers(
         title="subcommands", 
         parser_class=lambda **kw: CommandParser(cmd, **kw)) 
    

    今私はすべての問題に遭遇していませんでしたが、​​への将来の変更がラムダではなく、実際のクラス失敗を使用して作ることができるということも可能です。議論はparser_classと呼ばれ、parser_makerparser_manufactureのようなものではないので、私はこのような変化を公正なゲームと見なします。

  2. でカスタムクラスを渡すのではなく、​​クラスのうちの1つを渡すだけでいいですか? 即時の問題はありませんが、意図しない結果が生じます。 CommandParserのコメントは、​​のスティックパーサーの動作が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が必要とする正しい動作を提供することによって、その問題を回避します。

  3. あなたはそれを追加することができますし、それはかなり簡単だった
1

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) 
+0

ここでは、システム終了を行うバニラのargparseを使用しています。これは望ましくないので、Djangoがクラスを継承し、その動作を取り除くのはこのためです。これは、Djangoプロジェクトと同じ基準を保つことが気になる場合には、これを実行するための推奨された方法ではありません – Joakim

関連する問題