2014-01-20 10:45:21 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Base classes for writing management commands (named commands which can
|
2014-07-26 19:21:52 +08:00
|
|
|
be executed through ``django-admin`` or ``manage.py``).
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2015-01-28 20:35:27 +08:00
|
|
|
from __future__ import unicode_literals
|
2013-10-15 02:24:57 +08:00
|
|
|
|
2007-10-14 00:02:54 +08:00
|
|
|
import os
|
|
|
|
import sys
|
2013-12-25 06:43:47 +08:00
|
|
|
import warnings
|
2013-10-16 22:24:59 +08:00
|
|
|
from argparse import ArgumentParser
|
|
|
|
from optparse import OptionParser
|
2007-10-14 00:02:54 +08:00
|
|
|
|
2007-09-10 05:57:59 +08:00
|
|
|
import django
|
2014-01-20 10:45:21 +08:00
|
|
|
from django.core import checks
|
2013-02-23 23:28:45 +08:00
|
|
|
from django.core.management.color import color_style, no_style
|
2014-12-29 01:10:12 +08:00
|
|
|
from django.db import connections
|
2015-06-23 01:54:35 +08:00
|
|
|
from django.utils.deprecation import RemovedInDjango110Warning
|
2012-08-30 04:40:51 +08:00
|
|
|
from django.utils.encoding import force_str
|
2007-08-16 14:06:55 +08:00
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2007-08-16 14:06:55 +08:00
|
|
|
class CommandError(Exception):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Exception class indicating a problem while executing a management
|
|
|
|
command.
|
|
|
|
|
|
|
|
If this exception is raised during the execution of a management
|
|
|
|
command, it will be caught and turned into a nicely-printed error
|
|
|
|
message to the appropriate output stream (i.e., stderr); as a
|
|
|
|
result, raising this exception (with a sensible description of the
|
|
|
|
error) is the preferred way to indicate that something has gone
|
|
|
|
wrong in the execution of a command.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-08-16 14:06:55 +08:00
|
|
|
pass
|
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2014-10-20 19:10:53 +08:00
|
|
|
class SystemCheckError(CommandError):
|
|
|
|
"""
|
|
|
|
The system check framework detected unrecoverable errors.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2013-10-16 22:24:59 +08:00
|
|
|
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
|
2014-12-07 05:00:09 +08:00
|
|
|
not (args or any(not arg.startswith('-') for arg in args))):
|
2014-06-15 00:12:43 +08:00
|
|
|
self.error(self.cmd.missing_args_message)
|
2013-10-16 22:24:59 +08:00
|
|
|
return super(CommandParser, self).parse_args(args, namespace)
|
|
|
|
|
|
|
|
def error(self, message):
|
2014-06-15 00:12:43 +08:00
|
|
|
if self.cmd._called_from_command_line:
|
|
|
|
super(CommandParser, self).error(message)
|
|
|
|
else:
|
|
|
|
raise CommandError("Error: %s" % message)
|
2013-10-16 22:24:59 +08:00
|
|
|
|
|
|
|
|
2007-09-22 00:19:20 +08:00
|
|
|
def handle_default_options(options):
|
|
|
|
"""
|
2008-09-22 14:03:24 +08:00
|
|
|
Include any default options that all commands should accept here
|
|
|
|
so that ManagementUtility can handle them before searching for
|
|
|
|
user commands.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2007-09-22 00:19:20 +08:00
|
|
|
"""
|
|
|
|
if options.settings:
|
|
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
|
|
|
|
if options.pythonpath:
|
|
|
|
sys.path.insert(0, options.pythonpath)
|
2007-10-14 00:40:20 +08:00
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2012-05-19 19:51:54 +08:00
|
|
|
class OutputWrapper(object):
|
|
|
|
"""
|
|
|
|
Wrapper around stdout/stderr
|
|
|
|
"""
|
2014-10-22 02:11:31 +08:00
|
|
|
@property
|
|
|
|
def style_func(self):
|
|
|
|
return self._style_func
|
|
|
|
|
|
|
|
@style_func.setter
|
|
|
|
def style_func(self, style_func):
|
2015-07-22 05:24:32 +08:00
|
|
|
if style_func and self.isatty():
|
2014-10-22 02:11:31 +08:00
|
|
|
self._style_func = style_func
|
|
|
|
else:
|
|
|
|
self._style_func = lambda x: x
|
|
|
|
|
2012-05-26 17:43:37 +08:00
|
|
|
def __init__(self, out, style_func=None, ending='\n'):
|
2012-05-19 19:51:54 +08:00
|
|
|
self._out = out
|
|
|
|
self.style_func = None
|
2012-05-26 17:43:37 +08:00
|
|
|
self.ending = ending
|
2012-05-19 19:51:54 +08:00
|
|
|
|
|
|
|
def __getattr__(self, name):
|
|
|
|
return getattr(self._out, name)
|
|
|
|
|
2015-07-22 05:24:32 +08:00
|
|
|
def isatty(self):
|
|
|
|
return hasattr(self._out, 'isatty') and self._out.isatty()
|
|
|
|
|
2012-05-26 17:43:37 +08:00
|
|
|
def write(self, msg, style_func=None, ending=None):
|
2013-05-17 22:33:36 +08:00
|
|
|
ending = self.ending if ending is None else ending
|
2012-05-19 19:51:54 +08:00
|
|
|
if ending and not msg.endswith(ending):
|
|
|
|
msg += ending
|
2014-10-22 02:11:31 +08:00
|
|
|
style_func = style_func or self.style_func
|
2012-08-30 04:40:51 +08:00
|
|
|
self._out.write(force_str(style_func(msg)))
|
2012-05-19 19:51:54 +08:00
|
|
|
|
|
|
|
|
2007-08-16 14:06:55 +08:00
|
|
|
class BaseCommand(object):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
The base class from which all management commands ultimately
|
|
|
|
derive.
|
|
|
|
|
|
|
|
Use this class if you want access to all of the mechanisms which
|
|
|
|
parse the command-line arguments and work out what code to call in
|
|
|
|
response; if you don't need to change any of that behavior,
|
|
|
|
consider using one of the subclasses defined in this file.
|
|
|
|
|
|
|
|
If you are interested in overriding/customizing various aspects of
|
|
|
|
the command-parsing and -execution behavior, the normal flow works
|
|
|
|
as follows:
|
|
|
|
|
2014-07-26 19:21:52 +08:00
|
|
|
1. ``django-admin`` or ``manage.py`` loads the command class
|
2008-09-22 14:03:24 +08:00
|
|
|
and calls its ``run_from_argv()`` method.
|
|
|
|
|
|
|
|
2. The ``run_from_argv()`` method calls ``create_parser()`` to get
|
2013-10-16 22:24:59 +08:00
|
|
|
an ``ArgumentParser`` for the arguments, parses them, performs
|
2008-09-22 14:03:24 +08:00
|
|
|
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``.
|
|
|
|
|
2012-05-27 02:50:44 +08:00
|
|
|
4. If ``handle()`` or ``execute()`` raised any exception (e.g.
|
|
|
|
``CommandError``), ``run_from_argv()`` will instead print an error
|
|
|
|
message to ``stderr``.
|
2008-09-22 14:03:24 +08:00
|
|
|
|
|
|
|
Thus, the ``handle()`` method is typically the starting point for
|
|
|
|
subclasses; many built-in commands and command types either place
|
|
|
|
all of their logic in ``handle()``, or perform some additional
|
|
|
|
parsing work in ``handle()`` and then delegate from it to more
|
|
|
|
specialized methods as needed.
|
|
|
|
|
|
|
|
Several attributes affect behavior at various steps along the way:
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
``args``
|
|
|
|
A string listing the arguments accepted by the command,
|
|
|
|
suitable for use in help messages; e.g., a command which takes
|
2013-12-25 06:43:47 +08:00
|
|
|
a list of application names might set this to '<app_label
|
|
|
|
app_label ...>'.
|
2008-09-22 14:03:24 +08:00
|
|
|
|
|
|
|
``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.
|
2015-06-23 01:54:35 +08:00
|
|
|
Deprecated and will be removed in Django 1.10.
|
2008-09-22 14:03:24 +08:00
|
|
|
|
|
|
|
``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``.
|
|
|
|
|
2014-01-20 10:45:21 +08:00
|
|
|
``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.
|
|
|
|
|
2013-02-04 07:53:48 +08:00
|
|
|
``leave_locale_alone``
|
|
|
|
A boolean indicating whether the locale set in settings should be
|
2015-01-04 03:27:18 +08:00
|
|
|
preserved during the execution of the command instead of translations
|
|
|
|
being deactivated.
|
2013-02-04 07:53:48 +08:00
|
|
|
|
|
|
|
Default value is ``False``.
|
|
|
|
|
|
|
|
Make sure you know what you are doing if you decide to change the value
|
2013-02-04 19:55:45 +08:00
|
|
|
of this option in your custom command if it creates database content
|
|
|
|
that is locale-sensitive and such content shouldn't contain any
|
2015-01-04 03:27:18 +08:00
|
|
|
translations (like it happens e.g. with django.contrib.auth
|
|
|
|
permissions) as activating any locale might cause unintended effects.
|
2013-02-04 07:53:48 +08:00
|
|
|
|
|
|
|
This option can't be False when the can_import_settings option is set
|
2015-01-04 03:27:18 +08:00
|
|
|
to False too because attempting to deactivate translations needs access
|
|
|
|
to settings. This condition will generate a CommandError.
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-08-16 14:06:55 +08:00
|
|
|
# Metadata about this command.
|
2013-10-16 22:24:59 +08:00
|
|
|
option_list = ()
|
2007-08-16 14:06:55 +08:00
|
|
|
help = ''
|
|
|
|
args = ''
|
|
|
|
|
|
|
|
# Configuration shortcuts that alter various logic.
|
2014-06-15 00:12:43 +08:00
|
|
|
_called_from_command_line = False
|
2007-08-16 14:06:55 +08:00
|
|
|
can_import_settings = True
|
2011-12-23 06:38:02 +08:00
|
|
|
output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;"
|
2013-02-04 07:53:48 +08:00
|
|
|
leave_locale_alone = False
|
2015-01-18 01:59:07 +08:00
|
|
|
requires_system_checks = True
|
2014-01-20 10:45:21 +08:00
|
|
|
|
2014-10-22 02:11:31 +08:00
|
|
|
def __init__(self, stdout=None, stderr=None, no_color=False):
|
|
|
|
self.stdout = OutputWrapper(stdout or sys.stdout)
|
|
|
|
self.stderr = OutputWrapper(stderr or sys.stderr)
|
|
|
|
if no_color:
|
|
|
|
self.style = no_style()
|
|
|
|
else:
|
|
|
|
self.style = color_style()
|
|
|
|
self.stderr.style_func = self.style.ERROR
|
2007-08-16 14:06:55 +08:00
|
|
|
|
2013-10-16 22:24:59 +08:00
|
|
|
@property
|
|
|
|
def use_argparse(self):
|
|
|
|
return not bool(self.option_list)
|
|
|
|
|
2007-09-10 05:57:59 +08:00
|
|
|
def get_version(self):
|
|
|
|
"""
|
2008-09-22 14:03:24 +08:00
|
|
|
Return the Django version, which should be correct for all
|
|
|
|
built-in Django commands. User-supplied commands should
|
|
|
|
override this method.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2007-09-10 05:57:59 +08:00
|
|
|
"""
|
|
|
|
return django.get_version()
|
|
|
|
|
2007-09-11 12:24:35 +08:00
|
|
|
def usage(self, subcommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Return a brief description of how to use this command, by
|
|
|
|
default from the attribute ``self.help``.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-09-11 12:24:35 +08:00
|
|
|
usage = '%%prog %s [options] %s' % (subcommand, self.args)
|
2007-09-10 05:57:59 +08:00
|
|
|
if self.help:
|
|
|
|
return '%s\n\n%s' % (usage, self.help)
|
|
|
|
else:
|
|
|
|
return usage
|
|
|
|
|
2007-09-11 12:24:35 +08:00
|
|
|
def create_parser(self, prog_name, subcommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-10-16 22:24:59 +08:00
|
|
|
Create and return the ``ArgumentParser`` which will be used to
|
2008-09-22 14:03:24 +08:00
|
|
|
parse the arguments to this command.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-10-16 22:24:59 +08:00
|
|
|
if not self.use_argparse:
|
2015-06-05 01:03:28 +08:00
|
|
|
def store_as_int(option, opt_str, value, parser):
|
|
|
|
setattr(parser.values, option.dest, int(value))
|
|
|
|
|
2013-10-16 22:24:59 +08:00
|
|
|
# Backwards compatibility: use deprecated optparse module
|
|
|
|
warnings.warn("OptionParser usage for Django management commands "
|
|
|
|
"is deprecated, use ArgumentParser instead",
|
2015-06-23 01:54:35 +08:00
|
|
|
RemovedInDjango110Warning)
|
2013-10-16 22:24:59 +08:00
|
|
|
parser = OptionParser(prog=prog_name,
|
|
|
|
usage=self.usage(subcommand),
|
|
|
|
version=self.get_version())
|
2015-06-05 01:03:28 +08:00
|
|
|
parser.add_option('-v', '--verbosity', action='callback', dest='verbosity', default=1,
|
|
|
|
type='choice', choices=['0', '1', '2', '3'], callback=store_as_int,
|
2013-10-16 22:24:59 +08:00
|
|
|
help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output')
|
|
|
|
parser.add_option('--settings',
|
2014-09-04 20:15:09 +08:00
|
|
|
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.'
|
|
|
|
),
|
|
|
|
)
|
2013-10-16 22:24:59 +08:00
|
|
|
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',
|
2014-08-02 16:22:02 +08:00
|
|
|
help='Raise on CommandError exceptions')
|
2013-10-16 22:24:59 +08:00
|
|
|
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:
|
2014-06-15 02:01:02 +08:00
|
|
|
parser = CommandParser(self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
|
|
|
|
description=self.help or None)
|
2013-10-16 22:24:59 +08:00
|
|
|
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',
|
2014-09-04 20:15:09 +08:00
|
|
|
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.'
|
|
|
|
),
|
|
|
|
)
|
2013-10-16 22:24:59 +08:00
|
|
|
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',
|
2014-08-02 16:22:02 +08:00
|
|
|
help='Raise on CommandError exceptions')
|
2013-10-16 22:24:59 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
def add_arguments(self, parser):
|
|
|
|
"""
|
|
|
|
Entry point for subclassed commands to add custom arguments.
|
|
|
|
"""
|
|
|
|
pass
|
2007-09-10 05:57:59 +08:00
|
|
|
|
2007-09-11 12:24:35 +08:00
|
|
|
def print_help(self, prog_name, subcommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Print the help message for this command, derived from
|
|
|
|
``self.usage()``.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-09-11 12:24:35 +08:00
|
|
|
parser = self.create_parser(prog_name, subcommand)
|
2007-09-10 05:57:59 +08:00
|
|
|
parser.print_help()
|
|
|
|
|
2007-09-11 11:46:35 +08:00
|
|
|
def run_from_argv(self, argv):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Set up any environment changes requested (e.g., Python path
|
2012-05-27 02:50:44 +08:00
|
|
|
and Django settings), then run this command. If the
|
|
|
|
command raises a ``CommandError``, intercept it and print it sensibly
|
2013-05-19 00:04:45 +08:00
|
|
|
to stderr. If the ``--traceback`` option is present or the raised
|
|
|
|
``Exception`` is not ``CommandError``, raise it.
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2014-06-15 00:12:43 +08:00
|
|
|
self._called_from_command_line = True
|
2007-09-11 12:24:35 +08:00
|
|
|
parser = self.create_parser(argv[0], argv[1])
|
2013-10-16 22:24:59 +08:00
|
|
|
|
|
|
|
if self.use_argparse:
|
|
|
|
options = parser.parse_args(argv[2:])
|
|
|
|
cmd_options = vars(options)
|
|
|
|
# Move positional args out of options to mimic legacy optparse
|
2014-08-18 06:29:49 +08:00
|
|
|
args = cmd_options.pop('args', ())
|
2013-10-16 22:24:59 +08:00
|
|
|
else:
|
|
|
|
options, args = parser.parse_args(argv[2:])
|
|
|
|
cmd_options = vars(options)
|
2007-09-22 00:19:20 +08:00
|
|
|
handle_default_options(options)
|
2012-05-27 02:50:44 +08:00
|
|
|
try:
|
2013-10-16 22:24:59 +08:00
|
|
|
self.execute(*args, **cmd_options)
|
2012-05-27 02:50:44 +08:00
|
|
|
except Exception as e:
|
2013-05-19 00:04:45 +08:00
|
|
|
if options.traceback or not isinstance(e, CommandError):
|
|
|
|
raise
|
|
|
|
|
2014-10-20 19:10:53 +08:00
|
|
|
# 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))
|
2012-05-27 02:50:44 +08:00
|
|
|
sys.exit(1)
|
2014-12-29 01:10:12 +08:00
|
|
|
finally:
|
|
|
|
connections.close_all()
|
2007-09-10 05:57:59 +08:00
|
|
|
|
2007-08-16 14:06:55 +08:00
|
|
|
def execute(self, *args, **options):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2014-01-20 10:45:21 +08:00
|
|
|
Try to execute this command, performing system checks if needed (as
|
2015-01-18 01:59:07 +08:00
|
|
|
controlled by the ``requires_system_checks`` attribute, except if
|
|
|
|
force-skipped).
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-02-23 23:28:45 +08:00
|
|
|
if options.get('no_color'):
|
|
|
|
self.style = no_style()
|
2014-10-22 02:11:31 +08:00
|
|
|
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)
|
2012-05-19 19:51:54 +08:00
|
|
|
|
2013-02-04 07:53:48 +08:00
|
|
|
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))
|
2015-01-04 03:27:18 +08:00
|
|
|
# Deactivate translations, because django-admin creates database
|
2013-02-04 07:53:48 +08:00
|
|
|
# content like permissions, and those shouldn't contain any
|
|
|
|
# translations.
|
2012-05-27 02:50:44 +08:00
|
|
|
from django.utils import translation
|
2013-02-04 07:53:48 +08:00
|
|
|
saved_locale = translation.get_language()
|
2015-01-04 03:27:18 +08:00
|
|
|
translation.deactivate_all()
|
2011-12-11 18:03:09 +08:00
|
|
|
|
2007-08-16 14:06:55 +08:00
|
|
|
try:
|
2014-01-20 10:45:21 +08:00
|
|
|
if (self.requires_system_checks and
|
2014-09-04 20:15:09 +08:00
|
|
|
not options.get('skip_validation') and # Remove at the end of deprecation for `skip_validation`.
|
2014-01-20 10:45:21 +08:00
|
|
|
not options.get('skip_checks')):
|
|
|
|
self.check()
|
2007-08-16 14:06:55 +08:00
|
|
|
output = self.handle(*args, **options)
|
|
|
|
if output:
|
|
|
|
if self.output_transaction:
|
2010-05-28 21:46:12 +08:00
|
|
|
# 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)]
|
2007-08-20 08:24:03 +08:00
|
|
|
if connection.ops.start_transaction_sql():
|
2012-05-19 19:51:54 +08:00
|
|
|
self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
|
2010-06-05 13:26:04 +08:00
|
|
|
self.stdout.write(output)
|
2007-08-16 14:06:55 +08:00
|
|
|
if self.output_transaction:
|
2014-01-24 07:04:47 +08:00
|
|
|
self.stdout.write('\n' + self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()))
|
2012-03-30 00:33:48 +08:00
|
|
|
finally:
|
2013-02-04 07:53:48 +08:00
|
|
|
if saved_locale is not None:
|
|
|
|
translation.activate(saved_locale)
|
2007-08-16 14:06:55 +08:00
|
|
|
|
2014-09-13 02:50:36 +08:00
|
|
|
def check(self, app_configs=None, tags=None, display_num_errors=False,
|
|
|
|
include_deployment_checks=False):
|
2007-08-16 14:06:55 +08:00
|
|
|
"""
|
2014-01-20 10:45:21 +08:00
|
|
|
Uses the system check framework to validate entire Django project.
|
|
|
|
Raises CommandError for any serious message (error or critical errors).
|
|
|
|
If there are only light messages (like warnings), they are printed to
|
|
|
|
stderr and no exception is raised.
|
|
|
|
"""
|
2014-09-13 02:50:36 +08:00
|
|
|
all_issues = checks.run_checks(
|
|
|
|
app_configs=app_configs,
|
|
|
|
tags=tags,
|
|
|
|
include_deployment_checks=include_deployment_checks,
|
|
|
|
)
|
2014-01-20 10:45:21 +08:00
|
|
|
|
2014-10-20 19:10:53 +08:00
|
|
|
header, body, footer = "", "", ""
|
2014-01-23 03:09:02 +08:00
|
|
|
visible_issue_count = 0 # excludes silenced warnings
|
|
|
|
|
2014-01-20 10:45:21 +08:00
|
|
|
if all_issues:
|
|
|
|
debugs = [e for e in all_issues if e.level < checks.INFO and not e.is_silenced()]
|
|
|
|
infos = [e for e in all_issues if checks.INFO <= e.level < checks.WARNING and not e.is_silenced()]
|
|
|
|
warnings = [e for e in all_issues if checks.WARNING <= e.level < checks.ERROR and not e.is_silenced()]
|
|
|
|
errors = [e for e in all_issues if checks.ERROR <= e.level < checks.CRITICAL]
|
|
|
|
criticals = [e for e in all_issues if checks.CRITICAL <= e.level]
|
|
|
|
sorted_issues = [
|
|
|
|
(criticals, 'CRITICALS'),
|
|
|
|
(errors, 'ERRORS'),
|
|
|
|
(warnings, 'WARNINGS'),
|
|
|
|
(infos, 'INFOS'),
|
|
|
|
(debugs, 'DEBUGS'),
|
|
|
|
]
|
|
|
|
|
|
|
|
for issues, group_name in sorted_issues:
|
|
|
|
if issues:
|
2014-01-23 03:09:02 +08:00
|
|
|
visible_issue_count += len(issues)
|
2014-01-20 10:45:21 +08:00
|
|
|
formatted = (
|
2014-10-20 19:10:53 +08:00
|
|
|
self.style.ERROR(force_str(e))
|
2014-01-20 10:45:21 +08:00
|
|
|
if e.is_serious()
|
2014-10-20 19:10:53 +08:00
|
|
|
else self.style.WARNING(force_str(e))
|
2014-01-20 10:45:21 +08:00
|
|
|
for e in issues)
|
|
|
|
formatted = "\n".join(sorted(formatted))
|
2014-10-20 19:10:53 +08:00
|
|
|
body += '\n%s:\n%s\n' % (group_name, formatted)
|
|
|
|
|
|
|
|
if visible_issue_count:
|
|
|
|
header = "System check identified some issues:\n"
|
2014-01-20 10:45:21 +08:00
|
|
|
|
2007-08-27 08:30:37 +08:00
|
|
|
if display_num_errors:
|
2014-10-20 19:10:53 +08:00
|
|
|
if visible_issue_count:
|
|
|
|
footer += '\n'
|
|
|
|
footer += "System check identified %s (%s silenced)." % (
|
2014-01-23 03:09:02 +08:00
|
|
|
"no issues" if visible_issue_count == 0 else
|
|
|
|
"1 issue" if visible_issue_count == 1 else
|
|
|
|
"%s issues" % visible_issue_count,
|
|
|
|
len(all_issues) - visible_issue_count,
|
2014-01-20 10:45:21 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
if any(e.is_serious() and not e.is_silenced() for e in all_issues):
|
2014-10-20 19:10:53 +08:00
|
|
|
msg = self.style.ERROR("SystemCheckError: %s" % header) + body + footer
|
|
|
|
raise SystemCheckError(msg)
|
|
|
|
else:
|
|
|
|
msg = header + body + footer
|
|
|
|
|
|
|
|
if msg:
|
|
|
|
if visible_issue_count:
|
|
|
|
self.stderr.write(msg, lambda x: x)
|
|
|
|
else:
|
|
|
|
self.stdout.write(msg)
|
2007-08-16 14:06:55 +08:00
|
|
|
|
|
|
|
def handle(self, *args, **options):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
The actual logic of the command. Subclasses must implement
|
|
|
|
this method.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-09-07 02:24:52 +08:00
|
|
|
raise NotImplementedError('subclasses of BaseCommand must provide a handle() method')
|
2007-08-16 14:06:55 +08:00
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2007-08-16 14:06:55 +08:00
|
|
|
class AppCommand(BaseCommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-12-25 06:43:47 +08:00
|
|
|
A management command which takes one or more installed application labels
|
|
|
|
as arguments, and does something with each of them.
|
2008-09-22 14:03:24 +08:00
|
|
|
|
|
|
|
Rather than implementing ``handle()``, subclasses must implement
|
2013-12-25 06:43:47 +08:00
|
|
|
``handle_app_config()``, which will be called once for each application.
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-10-16 22:24:59 +08:00
|
|
|
missing_args_message = "Enter at least one application label."
|
|
|
|
|
|
|
|
def add_arguments(self, parser):
|
|
|
|
parser.add_argument('args', metavar='app_label', nargs='+',
|
|
|
|
help='One or more application label.')
|
2007-08-16 14:06:55 +08:00
|
|
|
|
|
|
|
def handle(self, *app_labels, **options):
|
2013-12-24 19:25:17 +08:00
|
|
|
from django.apps import apps
|
2007-08-16 14:06:55 +08:00
|
|
|
try:
|
2013-12-24 19:25:17 +08:00
|
|
|
app_configs = [apps.get_app_config(app_label) for app_label in app_labels]
|
2013-12-14 18:11:52 +08:00
|
|
|
except (LookupError, ImportError) as e:
|
2007-08-16 14:06:55 +08:00
|
|
|
raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
|
|
|
|
output = []
|
2013-12-15 01:51:58 +08:00
|
|
|
for app_config in app_configs:
|
2013-12-25 06:43:47 +08:00
|
|
|
app_output = self.handle_app_config(app_config, **options)
|
2007-08-16 14:06:55 +08:00
|
|
|
if app_output:
|
|
|
|
output.append(app_output)
|
|
|
|
return '\n'.join(output)
|
|
|
|
|
2013-12-25 06:43:47 +08:00
|
|
|
def handle_app_config(self, app_config, **options):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-12-25 06:43:47 +08:00
|
|
|
Perform the command's actions for app_config, an AppConfig instance
|
|
|
|
corresponding to an application label given on the command line.
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2015-01-18 01:32:20 +08:00
|
|
|
raise NotImplementedError(
|
|
|
|
"Subclasses of AppCommand must provide"
|
|
|
|
"a handle_app_config() method.")
|
2007-08-16 14:06:55 +08:00
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2007-08-16 22:34:01 +08:00
|
|
|
class LabelCommand(BaseCommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
A management command which takes one or more arbitrary arguments
|
|
|
|
(labels) on the command line, and does something with each of
|
|
|
|
them.
|
|
|
|
|
|
|
|
Rather than implementing ``handle()``, subclasses must implement
|
|
|
|
``handle_label()``, which will be called once for each label.
|
|
|
|
|
|
|
|
If the arguments should be names of installed applications, use
|
|
|
|
``AppCommand`` instead.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-08-16 22:34:01 +08:00
|
|
|
label = 'label'
|
2013-10-16 22:24:59 +08:00
|
|
|
missing_args_message = "Enter at least one %s." % label
|
2007-08-17 03:14:09 +08:00
|
|
|
|
2013-10-16 22:24:59 +08:00
|
|
|
def add_arguments(self, parser):
|
|
|
|
parser.add_argument('args', metavar=self.label, nargs='+')
|
2007-08-16 22:34:01 +08:00
|
|
|
|
2013-10-16 22:24:59 +08:00
|
|
|
def handle(self, *labels, **options):
|
2007-08-16 22:34:01 +08:00
|
|
|
output = []
|
|
|
|
for label in labels:
|
|
|
|
label_output = self.handle_label(label, **options)
|
|
|
|
if label_output:
|
|
|
|
output.append(label_output)
|
|
|
|
return '\n'.join(output)
|
|
|
|
|
|
|
|
def handle_label(self, label, **options):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Perform the command's actions for ``label``, which will be the
|
|
|
|
string as given on the command line.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-09-07 02:24:52 +08:00
|
|
|
raise NotImplementedError('subclasses of LabelCommand must provide a handle_label() method')
|
2007-08-16 22:34:01 +08:00
|
|
|
|
2011-12-23 06:38:02 +08:00
|
|
|
|
2007-08-16 22:34:01 +08:00
|
|
|
class NoArgsCommand(BaseCommand):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
A command which takes no arguments on the command line.
|
|
|
|
|
|
|
|
Rather than implementing ``handle()``, subclasses must implement
|
|
|
|
``handle_noargs()``; ``handle()`` itself is overridden to ensure
|
|
|
|
no arguments are passed to the command.
|
|
|
|
|
|
|
|
Attempting to pass arguments will raise ``CommandError``.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2007-08-16 22:34:01 +08:00
|
|
|
args = ''
|
|
|
|
|
2014-06-18 07:07:54 +08:00
|
|
|
def __init__(self):
|
|
|
|
warnings.warn(
|
2015-06-23 01:54:35 +08:00
|
|
|
"NoArgsCommand class is deprecated and will be removed in Django 1.10. "
|
2014-06-18 07:07:54 +08:00
|
|
|
"Use BaseCommand instead, which takes no arguments by default.",
|
2015-06-23 01:54:35 +08:00
|
|
|
RemovedInDjango110Warning
|
2014-06-18 07:07:54 +08:00
|
|
|
)
|
|
|
|
super(NoArgsCommand, self).__init__()
|
|
|
|
|
2007-08-16 22:34:01 +08:00
|
|
|
def handle(self, *args, **options):
|
2007-10-14 02:45:49 +08:00
|
|
|
if args:
|
2007-08-16 22:34:01 +08:00
|
|
|
raise CommandError("Command doesn't accept any arguments")
|
|
|
|
return self.handle_noargs(**options)
|
|
|
|
|
|
|
|
def handle_noargs(self, **options):
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
|
|
|
Perform this command's actions.
|
2010-03-18 21:24:11 +08:00
|
|
|
|
2008-09-22 14:03:24 +08:00
|
|
|
"""
|
2013-09-07 02:24:52 +08:00
|
|
|
raise NotImplementedError('subclasses of NoArgsCommand must provide a handle_noargs() method')
|