import django from django.core.exceptions import ImproperlyConfigured from django.core.management.color import color_style import itertools from optparse import make_option, OptionParser import sys import os class CommandError(Exception): pass class BaseCommand(object): # Metadata about this command. option_list = ( 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".'), ) help = '' args = '' # Configuration shortcuts that alter various logic. can_import_settings = True requires_model_validation = True output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;" def __init__(self): self.style = color_style() def get_version(self): """ Returns the Django version, which should be correct for all built-in Django commands. User-supplied commands should override this method. """ return django.get_version() def usage(self, subcommand): usage = '%%prog %s [options] %s' % (subcommand, self.args) if self.help: return '%s\n\n%s' % (usage, self.help) else: return usage def create_parser(self, prog_name, subcommand): return OptionParser(prog=prog_name, usage=self.usage(subcommand), version=self.get_version(), option_list=self.option_list) def print_help(self, prog_name, subcommand): parser = self.create_parser(prog_name, subcommand) parser.print_help() def run_from_argv(self, argv): parser = self.create_parser(argv[0], argv[1]) options, args = parser.parse_args(argv[2:]) if options.settings: os.environ['DJANGO_SETTINGS_MODULE'] = options.settings if options.pythonpath: sys.path.insert(0, options.pythonpath) self.execute(*args, **options.__dict__) def execute(self, *args, **options): # 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. if self.can_import_settings: from django.utils import translation translation.activate('en-us') try: if self.requires_model_validation: self.validate() 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 connection if connection.ops.start_transaction_sql(): print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()) print output if self.output_transaction: print self.style.SQL_KEYWORD("COMMIT;") except CommandError, e: sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e))) sys.exit(1) def validate(self, app=None, display_num_errors=False): """ Validates the given app, raising CommandError for any errors. If app is None, then this will validate all installed apps. """ from django.core.management.validation import get_validation_errors try: from cStringIO import StringIO except ImportError: from StringIO import StringIO s = StringIO() 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) if display_num_errors: print "%s error%s found" % (num_errors, num_errors != 1 and 's' or '') def handle(self, *args, **options): raise NotImplementedError() class AppCommand(BaseCommand): args = '' 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] except (ImproperlyConfigured, ImportError), e: 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): raise NotImplementedError() class LabelCommand(BaseCommand): args = '