1 from django.core.management.base import NoArgsCommand |
|
2 from django.core.management.color import no_style |
|
3 from django.utils.importlib import import_module |
|
4 from optparse import make_option |
1 from optparse import make_option |
5 import sys |
2 import sys |
6 |
3 |
7 try: |
4 from django.conf import settings |
8 set |
5 from django.core.management.base import NoArgsCommand |
9 except NameError: |
6 from django.core.management.color import no_style |
10 from sets import Set as set # Python 2.3 fallback |
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 |
11 |
12 |
12 class Command(NoArgsCommand): |
13 class Command(NoArgsCommand): |
13 option_list = NoArgsCommand.option_list + ( |
14 option_list = NoArgsCommand.option_list + ( |
14 make_option('--noinput', action='store_false', dest='interactive', default=True, |
15 make_option('--noinput', action='store_false', dest='interactive', default=True, |
15 help='Tells Django to NOT prompt the user for input of any kind.'), |
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.'), |
16 ) |
20 ) |
17 help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." |
21 help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." |
18 |
22 |
19 def handle_noargs(self, **options): |
23 def handle_noargs(self, **options): |
20 from django.db import connection, transaction, models |
|
21 from django.conf import settings |
|
22 from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal |
|
23 |
24 |
24 verbosity = int(options.get('verbosity', 1)) |
25 verbosity = int(options.get('verbosity', 1)) |
25 interactive = options.get('interactive') |
26 interactive = options.get('interactive') |
26 show_traceback = options.get('traceback', False) |
27 show_traceback = options.get('traceback', False) |
27 |
28 |
44 # PyPy uses "No module named myproject.myapp.management" |
45 # PyPy uses "No module named myproject.myapp.management" |
45 msg = exc.args[0] |
46 msg = exc.args[0] |
46 if not msg.startswith('No module named') or 'management' not in msg: |
47 if not msg.startswith('No module named') or 'management' not in msg: |
47 raise |
48 raise |
48 |
49 |
|
50 db = options.get('database', DEFAULT_DB_ALIAS) |
|
51 connection = connections[db] |
49 cursor = connection.cursor() |
52 cursor = connection.cursor() |
50 |
53 |
51 # Get a list of already installed *models* so that references work right. |
54 # Get a list of already installed *models* so that references work right. |
52 tables = connection.introspection.table_names() |
55 tables = connection.introspection.table_names() |
53 seen_models = connection.introspection.installed_models(tables) |
56 seen_models = connection.introspection.installed_models(tables) |
54 created_models = set() |
57 created_models = set() |
55 pending_references = {} |
58 pending_references = {} |
56 |
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 |
57 # Create the tables for each model |
78 # Create the tables for each model |
58 for app in models.get_apps(): |
79 for app_name, model_list in manifest.items(): |
59 app_name = app.__name__.split('.')[-2] |
|
60 model_list = models.get_models(app) |
|
61 for model in model_list: |
80 for model in model_list: |
62 # Create the model's database table, if it doesn't already exist. |
81 # Create the model's database table, if it doesn't already exist. |
63 if verbosity >= 2: |
82 if verbosity >= 2: |
64 print "Processing %s.%s model" % (app_name, model._meta.object_name) |
83 print "Processing %s.%s model" % (app_name, model._meta.object_name) |
65 if connection.introspection.table_name_converter(model._meta.db_table) in tables: |
|
66 continue |
|
67 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) |
84 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) |
68 seen_models.add(model) |
85 seen_models.add(model) |
69 created_models.add(model) |
86 created_models.add(model) |
70 for refto, refs in references.items(): |
87 for refto, refs in references.items(): |
71 pending_references.setdefault(refto, []).extend(refs) |
88 pending_references.setdefault(refto, []).extend(refs) |
76 print "Creating table %s" % model._meta.db_table |
93 print "Creating table %s" % model._meta.db_table |
77 for statement in sql: |
94 for statement in sql: |
78 cursor.execute(statement) |
95 cursor.execute(statement) |
79 tables.append(connection.introspection.table_name_converter(model._meta.db_table)) |
96 tables.append(connection.introspection.table_name_converter(model._meta.db_table)) |
80 |
97 |
81 # Create the m2m tables. This must be done after all tables have been created |
|
82 # to ensure that all referred tables will exist. |
|
83 for app in models.get_apps(): |
|
84 app_name = app.__name__.split('.')[-2] |
|
85 model_list = models.get_models(app) |
|
86 for model in model_list: |
|
87 if model in created_models: |
|
88 sql = connection.creation.sql_for_many_to_many(model, self.style) |
|
89 if sql: |
|
90 if verbosity >= 2: |
|
91 print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name) |
|
92 for statement in sql: |
|
93 cursor.execute(statement) |
|
94 |
98 |
95 transaction.commit_unless_managed() |
99 transaction.commit_unless_managed(using=db) |
96 |
100 |
97 # Send the post_syncdb signal, so individual apps can do whatever they need |
101 # Send the post_syncdb signal, so individual apps can do whatever they need |
98 # to do at this point. |
102 # to do at this point. |
99 emit_post_sync_signal(created_models, verbosity, interactive) |
103 emit_post_sync_signal(created_models, verbosity, interactive, db) |
100 |
104 |
101 # The connection may have been closed by a syncdb handler. |
105 # The connection may have been closed by a syncdb handler. |
102 cursor = connection.cursor() |
106 cursor = connection.cursor() |
103 |
107 |
104 # Install custom SQL for the app (but only if this |
108 # Install custom SQL for the app (but only if this |
105 # is a model we've just created) |
109 # is a model we've just created) |
106 for app in models.get_apps(): |
110 for app_name, model_list in manifest.items(): |
107 app_name = app.__name__.split('.')[-2] |
111 for model in model_list: |
108 for model in models.get_models(app): |
|
109 if model in created_models: |
112 if model in created_models: |
110 custom_sql = custom_sql_for_model(model, self.style) |
113 custom_sql = custom_sql_for_model(model, self.style, connection) |
111 if custom_sql: |
114 if custom_sql: |
112 if verbosity >= 1: |
115 if verbosity >= 1: |
113 print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name) |
116 print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name) |
114 try: |
117 try: |
115 for sql in custom_sql: |
118 for sql in custom_sql: |
118 sys.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \ |
121 sys.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \ |
119 (app_name, model._meta.object_name, e)) |
122 (app_name, model._meta.object_name, e)) |
120 if show_traceback: |
123 if show_traceback: |
121 import traceback |
124 import traceback |
122 traceback.print_exc() |
125 traceback.print_exc() |
123 transaction.rollback_unless_managed() |
126 transaction.rollback_unless_managed(using=db) |
124 else: |
127 else: |
125 transaction.commit_unless_managed() |
128 transaction.commit_unless_managed(using=db) |
126 else: |
129 else: |
127 if verbosity >= 2: |
130 if verbosity >= 2: |
128 print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name) |
131 print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name) |
|
132 |
129 # Install SQL indicies for all newly created models |
133 # Install SQL indicies for all newly created models |
130 for app in models.get_apps(): |
134 for app_name, model_list in manifest.items(): |
131 app_name = app.__name__.split('.')[-2] |
135 for model in model_list: |
132 for model in models.get_models(app): |
|
133 if model in created_models: |
136 if model in created_models: |
134 index_sql = connection.creation.sql_indexes_for_model(model, self.style) |
137 index_sql = connection.creation.sql_indexes_for_model(model, self.style) |
135 if index_sql: |
138 if index_sql: |
136 if verbosity >= 1: |
139 if verbosity >= 1: |
137 print "Installing index for %s.%s model" % (app_name, model._meta.object_name) |
140 print "Installing index for %s.%s model" % (app_name, model._meta.object_name) |
139 for sql in index_sql: |
142 for sql in index_sql: |
140 cursor.execute(sql) |
143 cursor.execute(sql) |
141 except Exception, e: |
144 except Exception, e: |
142 sys.stderr.write("Failed to install index for %s.%s model: %s\n" % \ |
145 sys.stderr.write("Failed to install index for %s.%s model: %s\n" % \ |
143 (app_name, model._meta.object_name, e)) |
146 (app_name, model._meta.object_name, e)) |
144 transaction.rollback_unless_managed() |
147 transaction.rollback_unless_managed(using=db) |
145 else: |
148 else: |
146 transaction.commit_unless_managed() |
149 transaction.commit_unless_managed(using=db) |
147 |
150 |
148 # Install the 'initial_data' fixture, using format discovery |
|
149 from django.core.management import call_command |
151 from django.core.management import call_command |
150 call_command('loaddata', 'initial_data', verbosity=verbosity) |
152 call_command('loaddata', 'initial_data', verbosity=verbosity, database=db) |