django.core.management-command
17612 ワード
1. ``django-admin`` or ``manage.py`` loads the command class
and calls its ``run_from_argv()`` method.
2. The ``run_from_argv()`` method calls ``create_parser()`` to get
an ``ArgumentParser`` for the arguments, parses them, performs
any environment changes requested by options like
``pythonpath``, and then calls the ``execute()`` method,
passing the parsed arguments.
3. The ``execute()`` method attempts to carry out the command by
calling the ``handle()`` method with the parsed arguments; any
output produced by ``handle()`` will be printed to standard
output and, if the command is intended to produce a block of
SQL statements, will be wrapped in ``BEGIN`` and ``COMMIT``.
4. If ``handle()`` or ``execute()`` raised any exception (e.g.
``CommandError``), ``run_from_argv()`` will instead print an error
message to ``stderr``.
これはコマンド実行のプロセスです.
最初のステップは後で話しますが、今は主に後で処理するプロセスコードを見て、BaseCommandによって実現されています.
BaseCommandクラスの実装コードが多いので,対応するメソッドを選択して解析する.
def run_from_argv(self, argv):
"""
Set up any environment changes requested (e.g., Python path
and Django settings), then run this command. If the
command raises a ``CommandError``, intercept it and print it sensibly
to stderr. If the ``--traceback`` option is present or the raised
``Exception`` is not ``CommandError``, raise it.
"""
self._called_from_command_line = True
parser = self.create_parser(argv[0], argv[1])
if self.use_argparse:
options = parser.parse_args(argv[2:])
cmd_options = vars(options)
# Move positional args out of options to mimic legacy optparse
args = cmd_options.pop('args', ())
else:
options, args = parser.parse_args(argv[2:])
cmd_options = vars(options)
handle_default_options(options)
try:
self.execute(*args, **cmd_options)
except Exception as e:
if options.traceback or not isinstance(e, CommandError):
raise
# SystemCheckError takes care of its own formatting.
if isinstance(e, SystemCheckError):
self.stderr.write(str(e), lambda x: x)
else:
self.stderr.write('%s: %s' % (e.__class__.__name__, e))
sys.exit(1)
run_from_argv()はまずparser=selfを呼び出す.create_parser(argv[0],argv[1])メソッド.
parserを得る後、selfを判断する.use_argparseで、返されるタイプを決定します.現在、2つの解析パラメータの方法があるため、1つはoptparseであり、django 2になる.0後に廃棄します.もう1つはargparserです.これは互換性を後方に保つためです.
argvパラメータフォーマットはsys.argv、コマンド実行時のパラメータ.例:python manage runserver 0.0.0.0:8000
ではargv=['manage','runserver','0.0.0.0:8000']である.
今createを見てparserメソッドの具体的なコード.
def create_parser(self, prog_name, subcommand):
"""
Create and return the ``ArgumentParser`` which will be used to
parse the arguments to this command.
"""
if not self.use_argparse:
# Backwards compatibility: use deprecated optparse module
warnings.warn("OptionParser usage for Django management commands "
"is deprecated, use ArgumentParser instead",
RemovedInDjango20Warning)
parser = OptionParser(prog=prog_name,
usage=self.usage(subcommand),
version=self.get_version())
parser.add_option('-v', '--verbosity', action='store', dest='verbosity', default='1',
type='choice', choices=['0', '1', '2', '3'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output')
parser.add_option('--settings',
help=(
'The Python path to a settings module, e.g. '
'"myproject.settings.main". If this isn\'t provided, the '
'DJANGO_SETTINGS_MODULE environment variable will be used.'
),
)
parser.add_option('--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
parser.add_option('--traceback', action='store_true',
help='Raise on CommandError exceptions')
parser.add_option('--no-color', action='store_true', dest='no_color', default=False,
help="Don't colorize the command output.")
for opt in self.option_list:
parser.add_option(opt)
else:
parser = CommandParser(self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
description=self.help or None)
parser.add_argument('--version', action='version', version=self.get_version())
parser.add_argument('-v', '--verbosity', action='store', dest='verbosity', default='1',
type=int, choices=[0, 1, 2, 3],
help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output')
parser.add_argument('--settings',
help=(
'The Python path to a settings module, e.g. '
'"myproject.settings.main". If this isn\'t provided, the '
'DJANGO_SETTINGS_MODULE environment variable will be used.'
),
)
parser.add_argument('--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
parser.add_argument('--traceback', action='store_true',
help='Raise on CommandError exceptions')
parser.add_argument('--no-color', action='store_true', dest='no_color', default=False,
help="Don't colorize the command output.")
if self.args:
# Keep compatibility and always accept positional arguments, like optparse when args is set
parser.add_argument('args', nargs='*')
self.add_arguments(parser)
return parser
まずselfを判断する.use_argparse,
@property
def use_argparse(self):
return not bool(self.option_list)
判断によりoption_リスト属性Noが空、option_ListはBaseCommandクラスで、デフォルトは空の元祖です.
option_list = ()
djangoは現在argpaseを使用する傾向にあるため,ここではargparseを使用する部分についてのみ説明する.
ここにまた新しいクラスCommandParserが現れました.
class CommandParser(ArgumentParser):
"""
Customized ArgumentParser class to improve some error messages and prevent
SystemExit in several occasions, as SystemExit is unacceptable when a
command is called programmatically.
"""
def __init__(self, cmd, **kwargs):
self.cmd = cmd
super(CommandParser, self).__init__(**kwargs)
def parse_args(self, args=None, namespace=None):
# Catch missing argument for a better error message
if (hasattr(self.cmd, 'missing_args_message') and
not (args or any(not arg.startswith('-') for arg in args))):
self.error(self.cmd.missing_args_message)
return super(CommandParser, self).parse_args(args, namespace)
def error(self, message):
if self.cmd._called_from_command_line:
super(CommandParser, self).error(message)
else:
raise CommandError("Error: %s" % message)
CommandParserはparseを書き直しただけだargs法.missing_を追加args_Messageの場合.
パラメータが欠けている場合をどのように判断しますか?
not (args or any(not arg.startswith('-') for arg in args))
この文をtrueに戻すと、パラメータが欠けていることを示します.
では
args or any(not arg.startswith('-') for arg in args)
falseに戻るべきです.ここでorオペレータを使用し、argsが空でなければargsを返すと、前の文はtrueを返すことになります.
argsが空の場合は、後ろの
any(not arg.startswith('-') for arg in args)
.ではargs=()、
not arg.startswith('-') for arg in args)
戻るのは相変わらず()で、これでは意味がありません.
error()メソッドも書き換え,放出異常を変えるだけである.
self.cmd._called_from_command_line,run_from_args()は直接trueに割り当てられます.
次にcreateを見てみましょうparserメソッド、CommandParserをインスタンス化した後、'--version'、'--verbosity'、'--settings'、'--pythonpath'、'--traceback'、'--no-color'オプションパラメータを追加します.
注意してargsという属性はself.argsが空でない場合、後続のパラメータはargsに収集されます.
parser.add_argument('args', nargs='*')
これは互換性を後方に保つために設定されています.argsプロパティを設定と、後続のselfになります.add_Arguments(parser)は機能しません.
def add_arguments(self, parser):
"""
Entry point for subclassed commands to add custom arguments.
"""
pass
add_Arguments()メソッドは、カスタムパラメータを追加するためにサブクラスで実装されます.
今run_に戻りますfrom_argv()メソッドでは,parserを作成すると解析パラメータとなる.
options = parser.parse_args(argv[2:])
cmd_options = vars(options)
# Move positional args out of options to mimic legacy optparse
args = cmd_options.pop('args', ())
varsは、返されるNameSpaceオブジェクトoptionsを辞書cmd_に変換します.options .
argsというパラメータを単独で提案した.
次にhandle_を呼び出すdefault_options(options)メソッド.
def handle_default_options(options):
"""
Include any default options that all commands should accept here
so that ManagementUtility can handle them before searching for
user commands.
"""
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
主にsettingsとpythonpathの2つのパラメータの処理を担当します.settings環境変数DJANGO_を変更することでプロファイルを作成SETTINGS_MODULE.pythonpathはsysを介してパケットとモジュールを検索するパスを追加する.path変数が変わります.
次にselfを呼び出す.execute(*args,**cmd_options)メソッド.
def execute(self, *args, **options):
"""
Try to execute this command, performing system checks if needed (as
controlled by attributes ``self.requires_system_checks`` and
``self.requires_model_validation``, except if force-skipped).
"""
if options.get('no_color'):
self.style = no_style()
self.stderr.style_func = None
if options.get('stdout'):
self.stdout = OutputWrapper(options['stdout'])
if options.get('stderr'):
self.stderr = OutputWrapper(options.get('stderr'), self.stderr.style_func)
if self.can_import_settings:
from django.conf import settings # NOQA
saved_locale = None
if not self.leave_locale_alone:
# Only mess with locales if we can assume we have a working
# settings file, because django.utils.translation requires settings
# (The final saying about whether the i18n machinery is active will be
# found in the value of the USE_I18N setting)
if not self.can_import_settings:
raise CommandError("Incompatible values of 'leave_locale_alone' "
"(%s) and 'can_import_settings' (%s) command "
"options." % (self.leave_locale_alone,
self.can_import_settings))
# Switch to US English, because django-admin creates database
# content like permissions, and those shouldn't contain any
# translations.
from django.utils import translation
saved_locale = translation.get_language()
translation.activate('en-us')
try:
if (self.requires_system_checks and
not options.get('skip_validation') and # Remove at the end of deprecation for `skip_validation`.
not options.get('skip_checks')):
self.check()
output = self.handle(*args, **options)
if output:
if self.output_transaction:
# This needs to be imported here, because it relies on
# settings.
from django.db import connections, DEFAULT_DB_ALIAS
connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
if connection.ops.start_transaction_sql():
self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
self.stdout.write(output)
if self.output_transaction:
self.stdout.write('
' + self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()))
finally:
if saved_locale is not None:
translation.activate(saved_locale)
前処理no_color,stdout,stderrのパラメータとself.can_import_settingsプロパティ.
そしてself.leave_locale_aloneプロパティ、translationを構成します.
そしてパラメータskip_に従ってvalidation, skip_checksとself.requires_system_checksプロパティ、selfを呼び出す.check()エラーをチェックします.
最後にhandle()メソッドを呼び出し、返された結果を出力します.
コマンド全体の実行過程は上記のとおりです.
コマンドをカスタマイズする場合は、主にクラスプロパティを設定します.
実装add_Arguments()カスタムパラメータを追加します.
handle()メソッドを実現し,独自の論理を実現する.
クラスのプロパティ:
``args``
A string listing the arguments accepted by the command,
suitable for use in help messages; e.g., a command which takes
a list of application names might set this to '<app_label
app_label ...>'.
``can_import_settings``
A boolean indicating whether the command needs to be able to
import Django settings; if ``True``, ``execute()`` will verify
that this is possible before proceeding. Default value is
``True``.
``help``
A short description of the command, which will be printed in
help messages.
``option_list``
This is the list of ``optparse`` options which will be fed
into the command's ``OptionParser`` for parsing arguments.
Deprecated and will be removed in Django 2.0.
``output_transaction``
A boolean indicating whether the command outputs SQL
statements; if ``True``, the output will automatically be
wrapped with ``BEGIN;`` and ``COMMIT;``. Default value is
``False``.
``requires_system_checks``
A boolean; if ``True``, entire Django project will be checked for errors
prior to executing the command. Default value is ``True``.
To validate an individual application's models
rather than all applications' models, call
``self.check(app_configs)`` from ``handle()``, where ``app_configs``
is the list of application's configuration provided by the
app registry.
``requires_model_validation``
DEPRECATED - This value will only be used if requires_system_checks
has not been provided. Defining both ``requires_system_checks`` and
``requires_model_validation`` will result in an error.
A boolean; if ``True``, validation of installed models will be
performed prior to executing the command. Default value is
``True``. To validate an individual application's models
rather than all applications' models, call
``self.validate(app_config)`` from ``handle()``, where ``app_config``
is the application's configuration provided by the app registry.
``leave_locale_alone``
A boolean indicating whether the locale set in settings should be
preserved during the execution of the command instead of being
forcibly set to 'en-us'.
Default value is ``False``.
Make sure you know what you are doing if you decide to change the value
of this option in your custom command if it creates database content
that is locale-sensitive and such content shouldn't contain any
translations (like it happens e.g. with django.contrim.auth
permissions) as making the locale differ from the de facto default
'en-us' might cause unintended effects.
This option can't be False when the can_import_settings option is set
to False too because attempting to set the locale needs access to
settings. This condition will generate a CommandError.
"""
実装add_arguments( ):
注意argsパラメータを指定するとadd_Arguments()が追加したパラメータは役に立たない.
handle(self,*args,*options)メソッドの実装:
argsプロパティが設定されている場合、optionsには--version、--verbosity、--settings、--pythonpath値のいくつかのプロパティしかありません.
argsパラメータはコマンドラインの残りのパラメータです.
argsプロパティが指定されていない場合、argsは空のメタグループ()です.optionsはパラメータを解析した辞書です.