web/lib/django/core/management/commands/syncdb.py
changeset 38 77b6da96e6f1
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 from optparse import make_option
       
     2 import sys
       
     3 
       
     4 from django.conf import settings
       
     5 from django.core.management.base import NoArgsCommand
       
     6 from django.core.management.color import no_style
       
     7 from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal
       
     8 from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
       
     9 from django.utils.datastructures import SortedDict
       
    10 from django.utils.importlib import import_module
       
    11 
       
    12 
       
    13 class Command(NoArgsCommand):
       
    14     option_list = NoArgsCommand.option_list + (
       
    15         make_option('--noinput', action='store_false', dest='interactive', default=True,
       
    16             help='Tells Django to NOT prompt the user for input of any kind.'),
       
    17         make_option('--database', action='store', dest='database',
       
    18             default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. '
       
    19                 'Defaults to the "default" database.'),
       
    20     )
       
    21     help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
       
    22 
       
    23     def handle_noargs(self, **options):
       
    24 
       
    25         verbosity = int(options.get('verbosity', 1))
       
    26         interactive = options.get('interactive')
       
    27         show_traceback = options.get('traceback', False)
       
    28 
       
    29         self.style = no_style()
       
    30 
       
    31         # Import the 'management' module within each installed app, to register
       
    32         # dispatcher events.
       
    33         for app_name in settings.INSTALLED_APPS:
       
    34             try:
       
    35                 import_module('.management', app_name)
       
    36             except ImportError, exc:
       
    37                 # This is slightly hackish. We want to ignore ImportErrors
       
    38                 # if the "management" module itself is missing -- but we don't
       
    39                 # want to ignore the exception if the management module exists
       
    40                 # but raises an ImportError for some reason. The only way we
       
    41                 # can do this is to check the text of the exception. Note that
       
    42                 # we're a bit broad in how we check the text, because different
       
    43                 # Python implementations may not use the same text.
       
    44                 # CPython uses the text "No module named management"
       
    45                 # PyPy uses "No module named myproject.myapp.management"
       
    46                 msg = exc.args[0]
       
    47                 if not msg.startswith('No module named') or 'management' not in msg:
       
    48                     raise
       
    49 
       
    50         db = options.get('database', DEFAULT_DB_ALIAS)
       
    51         connection = connections[db]
       
    52         cursor = connection.cursor()
       
    53 
       
    54         # Get a list of already installed *models* so that references work right.
       
    55         tables = connection.introspection.table_names()
       
    56         seen_models = connection.introspection.installed_models(tables)
       
    57         created_models = set()
       
    58         pending_references = {}
       
    59 
       
    60         # Build the manifest of apps and models that are to be synchronized
       
    61         all_models = [
       
    62             (app.__name__.split('.')[-2],
       
    63                 [m for m in models.get_models(app, include_auto_created=True)
       
    64                 if router.allow_syncdb(db, m)])
       
    65             for app in models.get_apps()
       
    66         ]
       
    67         def model_installed(model):
       
    68             opts = model._meta
       
    69             converter = connection.introspection.table_name_converter
       
    70             return not ((converter(opts.db_table) in tables) or
       
    71                 (opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
       
    72 
       
    73         manifest = SortedDict(
       
    74             (app_name, filter(model_installed, model_list))
       
    75             for app_name, model_list in all_models
       
    76         )
       
    77 
       
    78         # Create the tables for each model
       
    79         for app_name, model_list in manifest.items():
       
    80             for model in model_list:
       
    81                 # Create the model's database table, if it doesn't already exist.
       
    82                 if verbosity >= 2:
       
    83                     print "Processing %s.%s model" % (app_name, model._meta.object_name)
       
    84                 sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
       
    85                 seen_models.add(model)
       
    86                 created_models.add(model)
       
    87                 for refto, refs in references.items():
       
    88                     pending_references.setdefault(refto, []).extend(refs)
       
    89                     if refto in seen_models:
       
    90                         sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
       
    91                 sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
       
    92                 if verbosity >= 1 and sql:
       
    93                     print "Creating table %s" % model._meta.db_table
       
    94                 for statement in sql:
       
    95                     cursor.execute(statement)
       
    96                 tables.append(connection.introspection.table_name_converter(model._meta.db_table))
       
    97 
       
    98 
       
    99         transaction.commit_unless_managed(using=db)
       
   100 
       
   101         # Send the post_syncdb signal, so individual apps can do whatever they need
       
   102         # to do at this point.
       
   103         emit_post_sync_signal(created_models, verbosity, interactive, db)
       
   104 
       
   105         # The connection may have been closed by a syncdb handler.
       
   106         cursor = connection.cursor()
       
   107 
       
   108         # Install custom SQL for the app (but only if this
       
   109         # is a model we've just created)
       
   110         for app_name, model_list in manifest.items():
       
   111             for model in model_list:
       
   112                 if model in created_models:
       
   113                     custom_sql = custom_sql_for_model(model, self.style, connection)
       
   114                     if custom_sql:
       
   115                         if verbosity >= 1:
       
   116                             print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
       
   117                         try:
       
   118                             for sql in custom_sql:
       
   119                                 cursor.execute(sql)
       
   120                         except Exception, e:
       
   121                             sys.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \
       
   122                                                 (app_name, model._meta.object_name, e))
       
   123                             if show_traceback:
       
   124                                 import traceback
       
   125                                 traceback.print_exc()
       
   126                             transaction.rollback_unless_managed(using=db)
       
   127                         else:
       
   128                             transaction.commit_unless_managed(using=db)
       
   129                     else:
       
   130                         if verbosity >= 2:
       
   131                             print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name)
       
   132 
       
   133         # Install SQL indicies for all newly created models
       
   134         for app_name, model_list in manifest.items():
       
   135             for model in model_list:
       
   136                 if model in created_models:
       
   137                     index_sql = connection.creation.sql_indexes_for_model(model, self.style)
       
   138                     if index_sql:
       
   139                         if verbosity >= 1:
       
   140                             print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
       
   141                         try:
       
   142                             for sql in index_sql:
       
   143                                 cursor.execute(sql)
       
   144                         except Exception, e:
       
   145                             sys.stderr.write("Failed to install index for %s.%s model: %s\n" % \
       
   146                                                 (app_name, model._meta.object_name, e))
       
   147                             transaction.rollback_unless_managed(using=db)
       
   148                         else:
       
   149                             transaction.commit_unless_managed(using=db)
       
   150 
       
   151         from django.core.management import call_command
       
   152         call_command('loaddata', 'initial_data', verbosity=verbosity, database=db)