ソースを参照

Fixed #29133 -- Fixed call_command() crash if a required option is passed in options.

Alex Tomic 7 年 前
コミット
a1a3e51561

+ 8 - 1
django/core/management/__init__.py

@@ -117,7 +117,14 @@ def call_command(command_name, *args, **options):
         for s_opt in parser._actions if s_opt.option_strings
     }
     arg_options = {opt_mapping.get(key, key): value for key, value in options.items()}
-    defaults = parser.parse_args(args=[str(a) for a in args])
+    parse_args = [str(a) for a in args]
+    # Any required arguments which are passed in via **options must must be
+    # passed to parse_args().
+    parse_args += [
+        '{}={}'.format(min(opt.option_strings), arg_options[opt.dest])
+        for opt in parser._actions if opt.required and opt.dest in options
+    ]
+    defaults = parser.parse_args(args=parse_args)
     defaults = dict(defaults._get_kwargs(), **arg_options)
     # Raise an error if any unknown options were passed.
     stealth_options = set(command.base_stealth_options + command.stealth_options)

+ 11 - 0
tests/user_commands/management/commands/required_option.py

@@ -0,0 +1,11 @@
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+
+    def add_arguments(self, parser):
+        parser.add_argument('-n', '--need-me', required=True)
+        parser.add_argument('-t', '--need-me-too', required=True, dest='needme2')
+
+    def handle(self, *args, **options):
+        self.stdout.write(','.join(options))

+ 12 - 0
tests/user_commands/tests.py

@@ -194,6 +194,18 @@ class CommandTests(SimpleTestCase):
         with self.assertRaisesMessage(TypeError, msg):
             management.call_command('dance', unrecognized=1, unrecognized2=1)
 
+    def test_call_command_with_required_parameters_in_options(self):
+        out = StringIO()
+        management.call_command('required_option', need_me='foo', needme2='bar', stdout=out)
+        self.assertIn('need_me', out.getvalue())
+        self.assertIn('needme2', out.getvalue())
+
+    def test_call_command_with_required_parameters_in_mixed_options(self):
+        out = StringIO()
+        management.call_command('required_option', '--need-me=foo', needme2='bar', stdout=out)
+        self.assertIn('need_me', out.getvalue())
+        self.assertIn('needme2', out.getvalue())
+
 
 class CommandRunTests(AdminScriptTestCase):
     """