2008-09-22 14:03:24 +08:00
"""
Base classes for writing management commands ( named commands which can
be executed through ` ` django - admin . py ` ` or ` ` manage . py ` ` ) .
"""
2007-10-14 00:02:54 +08:00
import os
import sys
2011-12-23 06:38:02 +08:00
2012-05-06 01:47:03 +08:00
from io import BytesIO
2007-10-14 00:02:54 +08:00
from optparse import make_option , OptionParser
2011-12-11 18:03:09 +08:00
import traceback
2007-10-14 00:02:54 +08:00
2007-09-10 05:57:59 +08:00
import django
2007-08-16 14:06:55 +08:00
from django . core . exceptions import ImproperlyConfigured
from django . core . management . color import color_style
2010-03-18 21:24:11 +08:00
from django . utils . encoding import smart_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
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
"""
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
if hasattr ( out , ' isatty ' ) and out . isatty ( ) :
self . style_func = style_func
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 )
2012-05-26 17:43:37 +08:00
def write ( self , msg , style_func = None , ending = None ) :
ending = ending is None and self . ending or ending
2012-05-19 19:51:54 +08:00
if ending and not msg . endswith ( ending ) :
msg + = ending
2012-05-26 17:43:37 +08:00
style_func = [ f for f in ( style_func , self . style_func , lambda x : x )
if f is not None ] [ 0 ]
self . _out . write ( smart_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 :
1. ` ` django - admin . py ` ` 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 ` ` OptionParser ` ` 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 ` ` .
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
a list of application names might set this to ' <appname
appname . . . > ' .
` ` 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.
` ` 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_model_validation ` `
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 ) ` ` from ` ` handle ( ) ` ` , where ` ` app ` ` is the
application ' s Python module.
2010-03-18 21:24:11 +08:00
2008-09-22 14:03:24 +08:00
"""
2007-08-16 14:06:55 +08:00
# Metadata about this command.
2007-09-10 05:57:59 +08:00
option_list = (
2008-10-02 20:57:13 +08:00
make_option ( ' -v ' , ' --verbosity ' , action = ' store ' , dest = ' verbosity ' , default = ' 1 ' ,
2010-08-07 14:58:14 +08:00
type = ' choice ' , choices = [ ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' ] ,
2011-12-04 01:34:52 +08:00
help = ' Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output ' ) ,
2007-09-10 05:57:59 +08:00
make_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. ' ) ,
make_option ( ' --pythonpath ' ,
help = ' A directory to add to the Python path, e.g. " /home/djangoprojects/myproject " . ' ) ,
2007-12-17 19:09:32 +08:00
make_option ( ' --traceback ' , action = ' store_true ' ,
help = ' Print traceback on exception ' ) ,
2007-09-10 05:57:59 +08:00
)
2007-08-16 14:06:55 +08:00
help = ' '
args = ' '
# Configuration shortcuts that alter various logic.
can_import_settings = True
requires_model_validation = True
2011-12-23 06:38:02 +08:00
output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;"
2007-08-16 14:06:55 +08:00
def __init__ ( self ) :
self . style = color_style ( )
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
"""
Create and return the ` ` OptionParser ` ` which will be used to
parse the arguments to this command .
2010-03-18 21:24:11 +08:00
2008-09-22 14:03:24 +08:00
"""
2007-09-10 05:57:59 +08:00
return OptionParser ( prog = prog_name ,
2007-09-11 12:24:35 +08:00
usage = self . usage ( subcommand ) ,
2007-09-10 05:57:59 +08:00
version = self . get_version ( ) ,
option_list = self . option_list )
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
to stderr .
2008-09-22 14:03:24 +08:00
"""
2007-09-11 12:24:35 +08:00
parser = self . create_parser ( argv [ 0 ] , argv [ 1 ] )
options , args = parser . parse_args ( argv [ 2 : ] )
2007-09-22 00:19:20 +08:00
handle_default_options ( options )
2012-05-27 02:50:44 +08:00
try :
self . execute ( * args , * * options . __dict__ )
except Exception as e :
if options . traceback :
self . stderr . write ( traceback . format_exc ( ) )
self . stderr . write ( ' %s : %s ' % ( e . __class__ . __name__ , e ) )
sys . exit ( 1 )
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
"""
Try to execute this command , performing model validation if
needed ( as controlled by the attribute
2012-05-27 02:50:44 +08:00
` ` self . requires_model_validation ` ` , except if force - skipped ) .
2008-09-22 14:03:24 +08:00
"""
2011-12-11 18:03:09 +08:00
2007-08-16 14:06:55 +08:00
# Switch to English, because django-admin.py creates database content
# like permissions, and those shouldn't contain any translations.
# But only do this if we can assume we have a working settings file,
# because django.utils.translation requires settings.
2011-11-07 19:28:31 +08:00
saved_lang = None
2012-05-19 19:51:54 +08:00
self . stdout = OutputWrapper ( options . get ( ' stdout ' , sys . stdout ) )
self . stderr = OutputWrapper ( options . get ( ' stderr ' , sys . stderr ) , self . style . ERROR )
2007-08-16 14:06:55 +08:00
if self . can_import_settings :
2012-05-27 02:50:44 +08:00
from django . utils import translation
saved_lang = translation . get_language ( )
translation . activate ( ' en-us ' )
2011-12-11 18:03:09 +08:00
2007-08-16 14:06:55 +08:00
try :
2012-05-01 13:40:04 +08:00
if self . requires_model_validation and not options . get ( ' skip_validation ' ) :
2007-08-16 14:06:55 +08:00
self . validate ( )
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 :
2012-05-19 19:51:54 +08:00
self . stdout . write ( ' \n ' + self . style . SQL_KEYWORD ( " COMMIT; " ) )
2012-03-30 00:33:48 +08:00
finally :
if saved_lang is not None :
translation . activate ( saved_lang )
2007-08-16 14:06:55 +08:00
2007-08-27 08:30:37 +08:00
def validate ( self , app = None , display_num_errors = False ) :
2007-08-16 14:06:55 +08:00
"""
Validates the given app , raising CommandError for any errors .
2010-03-18 21:24:11 +08:00
2007-08-16 14:06:55 +08:00
If app is None , then this will validate all installed apps .
2010-03-18 21:24:11 +08:00
2007-08-16 14:06:55 +08:00
"""
from django . core . management . validation import get_validation_errors
2012-05-06 01:47:03 +08:00
s = BytesIO ( )
2007-08-16 14:06:55 +08:00
num_errors = get_validation_errors ( s , app )
if num_errors :
s . seek ( 0 )
error_text = s . read ( )
raise CommandError ( " One or more models did not validate: \n %s " % error_text )
2007-08-27 08:30:37 +08:00
if display_num_errors :
2012-05-19 19:51:54 +08:00
self . stdout . write ( " %s error %s found " % ( num_errors , num_errors != 1 and ' s ' or ' ' ) )
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
"""
2007-08-16 14:06:55 +08:00
raise NotImplementedError ( )
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
"""
A management command which takes one or more installed application
names as arguments , and does something with each of them .
Rather than implementing ` ` handle ( ) ` ` , subclasses must implement
` ` handle_app ( ) ` ` , which will be called once for each application .
2010-03-18 21:24:11 +08:00
2008-09-22 14:03:24 +08:00
"""
2007-09-10 05:57:59 +08:00
args = ' <appname appname ...> '
2007-08-16 14:06:55 +08:00
def handle ( self , * app_labels , * * options ) :
from django . db import models
if not app_labels :
raise CommandError ( ' Enter at least one appname. ' )
try :
app_list = [ models . get_app ( app_label ) for app_label in app_labels ]
2012-04-29 00:09:37 +08:00
except ( ImproperlyConfigured , 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 = [ ]
for app in app_list :
app_output = self . handle_app ( app , * * options )
if app_output :
output . append ( app_output )
return ' \n ' . join ( output )
def handle_app ( self , app , * * options ) :
2008-09-22 14:03:24 +08:00
"""
Perform the command ' s actions for ``app``, which will be the
Python module corresponding to an application name given on
the command line .
2010-03-18 21:24:11 +08:00
2008-09-22 14:03:24 +08:00
"""
2007-08-16 14:06:55 +08:00
raise NotImplementedError ( )
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-09-10 05:57:59 +08:00
args = ' <label label ...> '
2007-08-16 22:34:01 +08:00
label = ' label '
2007-08-17 03:14:09 +08:00
2007-08-16 22:34:01 +08:00
def handle ( self , * labels , * * options ) :
if not labels :
raise CommandError ( ' Enter at least one %s . ' % self . label )
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
"""
2007-08-16 22:34:01 +08:00
raise NotImplementedError ( )
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 = ' '
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
"""
2007-08-16 22:34:01 +08:00
raise NotImplementedError ( )