2016-04-18 12 views
5

Tytuł naprawdę mówi wszystko, ale obecnie mam to, ale to nie działa:Czy jest możliwe utworzenie akapitów w komendzie zarządzania 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." 
     ) 

Moje specyficzny pomysł jest stworzenie jedno polecenie, które ma podpoleceń do pobierania zawartości XML lub do analizowania go do bazy danych .

+0

Nie wiedząc, co jest w 'parser' już, lub co' django' robi to z nim później, nie mogę powiedzieć . Poza tym twoje definicje w akapicie wyglądają dobrze.Ale, jak możesz zauważyć na innych pytaniach SO, ustawianie akapitu z innymi argumentami, pozycjami i/lub opcjami, może być trudne. Podobnie jak w przypadku diagnostyki, dodaj "print parser._actions" na początku swojej funkcji. – hpaulj

+0

http://stackoverflow.com/questions/31919101/djangos-call-command-fails-w-missing- wymagany dokument, to jedno poprzednie pytanie dotyczące zarówno argparse, jak i django. Wygląda na to, że django używało optparse, ale ostatnio dodało alternatywę argparse. – hpaulj

Odpowiedz

7

Jest to możliwe, ale wymaga to trochę pracy:

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) 

Po wywołaniu add_subparsers domyślnie argparse tworzy nowy parser, który jest tej samej klasy co parsera, na których nazwie add_subparser. Tak się składa, że ​​analizator składni, który można uzyskać w parser, jest instancją CommandParser (zdefiniowaną w django.core.management.base). CommandParser klasa wymaga się cmd argumentu przed **kwargs (podczas gdy domyślna klasa parser dostarczone przez argparse zajmuje tylko **kwargs):

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

Więc kiedy spróbujesz dodać subparser, to nie dlatego, że konstruktor jest wywoływana tylko z **kwargs i brak argumentu cmd.

Powyższy kod rozwiązuje problem przez podanie w argumencie parser_class argumentu klasy, która dodaje brakujący parametr.

warte rozważenia:

  1. W powyższym kodzie, tworzę nową klasę ponieważ nazwa parser_class sugeruje, że to, co powinno być przekazywana jest prawdziwa klasa. Jednak ta działa również:

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

    Teraz I już nie napotkasz żadnych problemów, ale możliwe jest, że przyszłe zmiany argparse mógł zrobić za pomocą lambda zamiast prawdziwą klasę niepowodzeniem. Ponieważ argument nazywa się parser_class i nie jest to coś takiego jak parser_maker lub parser_manufacture, uważam, że taka zmiana jest uczciwa.

  2. Nie można po prostu przekazać jednej z klas czasowych argparse zamiast przechodzić klasę niestandardową w parser_class? Nie będzie problemu, ale wystąpią niezamierzone konsekwencje. Komentarze w CommandParser pokazują, że zachowanie parsera stick kijów argparse jest niepożądane dla poleceń Django. W szczególności, docstring dla państw Klasa:

    """ 
    Customized ArgumentParser class to improve some error messages and prevent 
    SystemExit in several occasions, as SystemExit is unacceptable when a 
    command is called programmatically. 
    """ 
    

    Jest to problem, który Jerzyk's answer cierpi. Rozwiązanie to pozwala uniknąć tego problemu, wywodząc się z CommandParser, zapewniając w ten sposób prawidłowe zachowanie wymagane przez Django.

1

można go dodać i to było całkiem proste:

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

Używasz tutaj wanilii argparse, która spowoduje wyjście z systemu. Jest to niepożądane, dlatego właśnie Django dziedziczy klasę i pozbywa się tego zachowania. Więc nie jest to zalecany sposób, aby to zrobić, jeśli zależy ci na zachowaniu tych samych standardów co projekt Django – Joakim

Powiązane problemy