1
from django.core.management.base import CommandError
8
from sets import Set as set # Python 2.3 fallback
10
def sql_create(app, style):
11
"Returns a list of the CREATE TABLE SQL statements for the given app."
12
from django.db import connection, models
13
from django.conf import settings
15
if settings.DATABASE_ENGINE == 'dummy':
16
# This must be the "dummy" database backend, which means the user
17
# hasn't set DATABASE_ENGINE.
18
raise CommandError("Django doesn't know which syntax to use for your SQL statements,\n" +
19
"because you haven't specified the DATABASE_ENGINE setting.\n" +
20
"Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.")
22
# Get installed models, so we generate REFERENCES right.
23
# We trim models from the current app so that the sqlreset command does not
24
# generate invalid SQL (leaving models out of known_models is harmless, so
25
# we can be conservative).
26
app_models = models.get_models(app)
28
tables = connection.introspection.table_names()
29
known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
30
pending_references = {}
32
for model in app_models:
33
output, references = connection.creation.sql_create_model(model, style, known_models)
34
final_output.extend(output)
35
for refto, refs in references.items():
36
pending_references.setdefault(refto, []).extend(refs)
37
if refto in known_models:
38
final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references))
39
final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references))
40
# Keep track of the fact that we've created the table for this model.
41
known_models.add(model)
43
# Create the many-to-many join tables.
44
for model in app_models:
45
final_output.extend(connection.creation.sql_for_many_to_many(model, style))
47
# Handle references to tables that are from other apps
48
# but don't exist physically.
49
not_installed_models = set(pending_references.keys())
50
if not_installed_models:
52
for model in not_installed_models:
53
alter_sql.extend(['-- ' + sql for sql in
54
connection.creation.sql_for_pending_references(model, style, pending_references)])
56
final_output.append('-- The following references should be added but depend on non-existent tables:')
57
final_output.extend(alter_sql)
61
def sql_delete(app, style):
62
"Returns a list of the DROP TABLE SQL statements for the given app."
63
from django.db import connection, models
64
from django.db.backends.util import truncate_name
65
from django.contrib.contenttypes import generic
67
# This should work even if a connection isn't available
69
cursor = connection.cursor()
73
# Figure out which tables already exist
75
table_names = connection.introspection.get_table_list(cursor)
81
# Output DROP TABLE statements for standard application tables.
84
references_to_delete = {}
85
app_models = models.get_models(app)
86
for model in app_models:
87
if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
88
# The table exists, so it needs to be dropped
90
for f in opts.local_fields:
91
if f.rel and f.rel.to not in to_delete:
92
references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
96
for model in app_models:
97
if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
98
output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
100
# Output DROP TABLE statements for many-to-many tables.
101
for model in app_models:
103
for f in opts.local_many_to_many:
104
if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names:
105
output.extend(connection.creation.sql_destroy_many_to_many(model, f, style))
107
# Close database connection explicitly, in case this output is being piped
108
# directly into a database client, to avoid locking issues.
113
return output[::-1] # Reverse it, to deal with table dependencies.
115
def sql_reset(app, style):
116
"Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
117
return sql_delete(app, style) + sql_all(app, style)
119
def sql_flush(style, only_django=False):
121
Returns a list of the SQL statements used to flush the database.
123
If only_django is True, then only table names that have associated Django
124
models and are in INSTALLED_APPS will be included.
126
from django.db import connection
128
tables = connection.introspection.django_table_names()
130
tables = connection.introspection.table_names()
131
statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
134
def sql_custom(app, style):
135
"Returns a list of the custom table modifying SQL statements for the given app."
136
from django.db.models import get_models
139
app_models = get_models(app)
140
app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
142
for model in app_models:
143
output.extend(custom_sql_for_model(model, style))
147
def sql_indexes(app, style):
148
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
149
from django.db import connection, models
151
for model in models.get_models(app):
152
output.extend(connection.creation.sql_indexes_for_model(model, style))
155
def sql_all(app, style):
156
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
157
return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style)
159
def custom_sql_for_model(model, style):
160
from django.db import models
161
from django.conf import settings
164
app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
167
# Post-creation SQL should come before any initial SQL data is loaded.
168
# However, this should not be done for fields that are part of a a parent
169
# model (via model inheritance).
170
nm = opts.init_name_map()
171
post_sql_fields = [f for f in opts.local_fields if hasattr(f, 'post_create_sql')]
172
for f in post_sql_fields:
173
output.extend(f.post_create_sql(style, model._meta.db_table))
175
# Some backends can't execute more than one SQL statement at a time,
176
# so split into separate statements.
177
statements = re.compile(r";[ \t]*$", re.M)
179
# Find custom SQL, if it's available.
180
sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
181
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
182
for sql_file in sql_files:
183
if os.path.exists(sql_file):
184
fp = open(sql_file, 'U')
185
for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
186
# Remove any comments from the file
187
statement = re.sub(ur"--.*([\n\Z]|$)", "", statement)
188
if statement.strip():
189
output.append(statement + u";")
195
def emit_post_sync_signal(created_models, verbosity, interactive):
196
from django.db import models
197
from django.dispatch import dispatcher
198
# Emit the post_sync signal for every application.
199
for app in models.get_apps():
200
app_name = app.__name__.split('.')[-2]
202
print "Running post-sync handlers for application", app_name
203
models.signals.post_syncdb.send(sender=app, app=app,
204
created_models=created_models, verbosity=verbosity,
205
interactive=interactive)