mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
Fixed #5461 -- Refactored the database backend code to use classes for the creation and introspection modules. Introduces a new validation module for DB-specific validation. This is a backwards incompatible change; see the wiki for details.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8296 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -6,5 +6,5 @@ class Command(NoArgsCommand):
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from django.db import runshell
|
||||
runshell()
|
||||
from django.db import connection
|
||||
connection.client.runshell()
|
||||
|
||||
@@ -13,11 +13,9 @@ class Command(NoArgsCommand):
|
||||
raise CommandError("Database inspection isn't supported for the currently selected database backend.")
|
||||
|
||||
def handle_inspection(self):
|
||||
from django.db import connection, get_introspection_module
|
||||
from django.db import connection
|
||||
import keyword
|
||||
|
||||
introspection_module = get_introspection_module()
|
||||
|
||||
table2model = lambda table_name: table_name.title().replace('_', '')
|
||||
|
||||
cursor = connection.cursor()
|
||||
@@ -32,17 +30,17 @@ class Command(NoArgsCommand):
|
||||
yield ''
|
||||
yield 'from django.db import models'
|
||||
yield ''
|
||||
for table_name in introspection_module.get_table_list(cursor):
|
||||
for table_name in connection.introspection.get_table_list(cursor):
|
||||
yield 'class %s(models.Model):' % table2model(table_name)
|
||||
try:
|
||||
relations = introspection_module.get_relations(cursor, table_name)
|
||||
relations = connection.introspection.get_relations(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
relations = {}
|
||||
try:
|
||||
indexes = introspection_module.get_indexes(cursor, table_name)
|
||||
indexes = connection.introspection.get_indexes(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
indexes = {}
|
||||
for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
|
||||
for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
|
||||
att_name = row[0].lower()
|
||||
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
||||
extra_params = {} # Holds Field parameters such as 'db_column'.
|
||||
@@ -65,7 +63,7 @@ class Command(NoArgsCommand):
|
||||
extra_params['db_column'] = att_name
|
||||
else:
|
||||
try:
|
||||
field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
|
||||
field_type = connection.introspection.data_types_reverse[row[1]]
|
||||
except KeyError:
|
||||
field_type = 'TextField'
|
||||
comment_notes.append('This field type is a guess.')
|
||||
|
||||
@@ -21,7 +21,7 @@ class Command(NoArgsCommand):
|
||||
def handle_noargs(self, **options):
|
||||
from django.db import connection, transaction, models
|
||||
from django.conf import settings
|
||||
from django.core.management.sql import table_names, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
|
||||
from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive')
|
||||
@@ -50,16 +50,9 @@ class Command(NoArgsCommand):
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
if connection.features.uses_case_insensitive_names:
|
||||
table_name_converter = lambda x: x.upper()
|
||||
else:
|
||||
table_name_converter = lambda x: x
|
||||
# Get a list of all existing database tables, so we know what needs to
|
||||
# be added.
|
||||
tables = [table_name_converter(name) for name in table_names()]
|
||||
|
||||
# Get a list of already installed *models* so that references work right.
|
||||
seen_models = installed_models(tables)
|
||||
tables = connection.introspection.table_names()
|
||||
seen_models = connection.introspection.installed_models(tables)
|
||||
created_models = set()
|
||||
pending_references = {}
|
||||
|
||||
@@ -71,21 +64,21 @@ class Command(NoArgsCommand):
|
||||
# Create the model's database table, if it doesn't already exist.
|
||||
if verbosity >= 2:
|
||||
print "Processing %s.%s model" % (app_name, model._meta.object_name)
|
||||
if table_name_converter(model._meta.db_table) in tables:
|
||||
if connection.introspection.table_name_converter(model._meta.db_table) in tables:
|
||||
continue
|
||||
sql, references = sql_model_create(model, self.style, seen_models)
|
||||
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
|
||||
seen_models.add(model)
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in seen_models:
|
||||
sql.extend(sql_for_pending_references(refto, self.style, pending_references))
|
||||
sql.extend(sql_for_pending_references(model, self.style, pending_references))
|
||||
sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
|
||||
sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
|
||||
if verbosity >= 1:
|
||||
print "Creating table %s" % model._meta.db_table
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
tables.append(table_name_converter(model._meta.db_table))
|
||||
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
|
||||
|
||||
# Create the m2m tables. This must be done after all tables have been created
|
||||
# to ensure that all referred tables will exist.
|
||||
@@ -94,7 +87,7 @@ class Command(NoArgsCommand):
|
||||
model_list = models.get_models(app)
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
sql = many_to_many_sql_for_model(model, self.style)
|
||||
sql = connection.creation.sql_for_many_to_many(model, self.style)
|
||||
if sql:
|
||||
if verbosity >= 2:
|
||||
print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
|
||||
@@ -140,7 +133,7 @@ class Command(NoArgsCommand):
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
for model in models.get_models(app):
|
||||
if model in created_models:
|
||||
index_sql = sql_indexes_for_model(model, self.style)
|
||||
index_sql = connection.creation.sql_indexes_for_model(model, self.style)
|
||||
if index_sql:
|
||||
if verbosity >= 1:
|
||||
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
|
||||
|
||||
@@ -18,13 +18,13 @@ class Command(BaseCommand):
|
||||
|
||||
def handle(self, *fixture_labels, **options):
|
||||
from django.core.management import call_command
|
||||
from django.test.utils import create_test_db
|
||||
from django.db import connection
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
addrport = options.get('addrport')
|
||||
|
||||
# Create a test database.
|
||||
db_name = create_test_db(verbosity=verbosity)
|
||||
db_name = connection.creation.create_test_db(verbosity=verbosity)
|
||||
|
||||
# Import the fixture data into the test database.
|
||||
call_command('loaddata', *fixture_labels, **{'verbosity': verbosity})
|
||||
|
||||
@@ -7,65 +7,9 @@ try:
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
def table_names():
|
||||
"Returns a list of all table names that exist in the database."
|
||||
from django.db import connection, get_introspection_module
|
||||
cursor = connection.cursor()
|
||||
return set(get_introspection_module().get_table_list(cursor))
|
||||
|
||||
def django_table_names(only_existing=False):
|
||||
"""
|
||||
Returns a list of all table names that have associated Django models and
|
||||
are in INSTALLED_APPS.
|
||||
|
||||
If only_existing is True, the resulting list will only include the tables
|
||||
that actually exist in the database.
|
||||
"""
|
||||
from django.db import models
|
||||
tables = set()
|
||||
for app in models.get_apps():
|
||||
for model in models.get_models(app):
|
||||
tables.add(model._meta.db_table)
|
||||
tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
|
||||
if only_existing:
|
||||
tables = [t for t in tables if t in table_names()]
|
||||
return tables
|
||||
|
||||
def installed_models(table_list):
|
||||
"Returns a set of all models that are installed, given a list of existing table names."
|
||||
from django.db import connection, models
|
||||
all_models = []
|
||||
for app in models.get_apps():
|
||||
for model in models.get_models(app):
|
||||
all_models.append(model)
|
||||
if connection.features.uses_case_insensitive_names:
|
||||
converter = lambda x: x.upper()
|
||||
else:
|
||||
converter = lambda x: x
|
||||
return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
|
||||
|
||||
def sequence_list():
|
||||
"Returns a list of information about all DB sequences for all models in all apps."
|
||||
from django.db import models
|
||||
|
||||
apps = models.get_apps()
|
||||
sequence_list = []
|
||||
|
||||
for app in apps:
|
||||
for model in models.get_models(app):
|
||||
for f in model._meta.local_fields:
|
||||
if isinstance(f, models.AutoField):
|
||||
sequence_list.append({'table': model._meta.db_table, 'column': f.column})
|
||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
||||
|
||||
for f in model._meta.local_many_to_many:
|
||||
sequence_list.append({'table': f.m2m_db_table(), 'column': None})
|
||||
|
||||
return sequence_list
|
||||
|
||||
def sql_create(app, style):
|
||||
"Returns a list of the CREATE TABLE SQL statements for the given app."
|
||||
from django.db import models
|
||||
from django.db import connection, models
|
||||
from django.conf import settings
|
||||
|
||||
if settings.DATABASE_ENGINE == 'dummy':
|
||||
@@ -81,23 +25,24 @@ def sql_create(app, style):
|
||||
# we can be conservative).
|
||||
app_models = models.get_models(app)
|
||||
final_output = []
|
||||
known_models = set([model for model in installed_models(table_names()) if model not in app_models])
|
||||
tables = connection.introspection.table_names()
|
||||
known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
|
||||
pending_references = {}
|
||||
|
||||
for model in app_models:
|
||||
output, references = sql_model_create(model, style, known_models)
|
||||
output, references = connection.creation.sql_create_model(model, style, known_models)
|
||||
final_output.extend(output)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in known_models:
|
||||
final_output.extend(sql_for_pending_references(refto, style, pending_references))
|
||||
final_output.extend(sql_for_pending_references(model, style, pending_references))
|
||||
final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references))
|
||||
final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references))
|
||||
# Keep track of the fact that we've created the table for this model.
|
||||
known_models.add(model)
|
||||
|
||||
# Create the many-to-many join tables.
|
||||
for model in app_models:
|
||||
final_output.extend(many_to_many_sql_for_model(model, style))
|
||||
final_output.extend(connection.creation.sql_for_many_to_many(model, style))
|
||||
|
||||
# Handle references to tables that are from other apps
|
||||
# but don't exist physically.
|
||||
@@ -106,7 +51,7 @@ def sql_create(app, style):
|
||||
alter_sql = []
|
||||
for model in not_installed_models:
|
||||
alter_sql.extend(['-- ' + sql for sql in
|
||||
sql_for_pending_references(model, style, pending_references)])
|
||||
connection.creation.sql_for_pending_references(model, style, pending_references)])
|
||||
if alter_sql:
|
||||
final_output.append('-- The following references should be added but depend on non-existent tables:')
|
||||
final_output.extend(alter_sql)
|
||||
@@ -115,10 +60,9 @@ def sql_create(app, style):
|
||||
|
||||
def sql_delete(app, style):
|
||||
"Returns a list of the DROP TABLE SQL statements for the given app."
|
||||
from django.db import connection, models, get_introspection_module
|
||||
from django.db import connection, models
|
||||
from django.db.backends.util import truncate_name
|
||||
from django.contrib.contenttypes import generic
|
||||
introspection = get_introspection_module()
|
||||
|
||||
# This should work even if a connection isn't available
|
||||
try:
|
||||
@@ -128,16 +72,11 @@ def sql_delete(app, style):
|
||||
|
||||
# Figure out which tables already exist
|
||||
if cursor:
|
||||
table_names = introspection.get_table_list(cursor)
|
||||
table_names = connection.introspection.get_table_list(cursor)
|
||||
else:
|
||||
table_names = []
|
||||
if connection.features.uses_case_insensitive_names:
|
||||
table_name_converter = lambda x: x.upper()
|
||||
else:
|
||||
table_name_converter = lambda x: x
|
||||
|
||||
output = []
|
||||
qn = connection.ops.quote_name
|
||||
|
||||
# Output DROP TABLE statements for standard application tables.
|
||||
to_delete = set()
|
||||
@@ -145,7 +84,7 @@ def sql_delete(app, style):
|
||||
references_to_delete = {}
|
||||
app_models = models.get_models(app)
|
||||
for model in app_models:
|
||||
if cursor and table_name_converter(model._meta.db_table) in table_names:
|
||||
if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
# The table exists, so it needs to be dropped
|
||||
opts = model._meta
|
||||
for f in opts.local_fields:
|
||||
@@ -155,40 +94,15 @@ def sql_delete(app, style):
|
||||
to_delete.add(model)
|
||||
|
||||
for model in app_models:
|
||||
if cursor and table_name_converter(model._meta.db_table) in table_names:
|
||||
# Drop the table now
|
||||
output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
|
||||
style.SQL_TABLE(qn(model._meta.db_table))))
|
||||
if connection.features.supports_constraints and model in references_to_delete:
|
||||
for rel_class, f in references_to_delete[model]:
|
||||
table = rel_class._meta.db_table
|
||||
col = f.column
|
||||
r_table = model._meta.db_table
|
||||
r_col = model._meta.get_field(f.rel.field_name).column
|
||||
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
|
||||
output.append('%s %s %s %s;' % \
|
||||
(style.SQL_KEYWORD('ALTER TABLE'),
|
||||
style.SQL_TABLE(qn(table)),
|
||||
style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
|
||||
style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
|
||||
del references_to_delete[model]
|
||||
if model._meta.has_auto_field:
|
||||
ds = connection.ops.drop_sequence_sql(model._meta.db_table)
|
||||
if ds:
|
||||
output.append(ds)
|
||||
if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
|
||||
|
||||
# Output DROP TABLE statements for many-to-many tables.
|
||||
for model in app_models:
|
||||
opts = model._meta
|
||||
for f in opts.local_many_to_many:
|
||||
if not f.creates_table:
|
||||
continue
|
||||
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
|
||||
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
|
||||
style.SQL_TABLE(qn(f.m2m_db_table()))))
|
||||
ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
|
||||
if ds:
|
||||
output.append(ds)
|
||||
if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names:
|
||||
output.extend(connection.creation.sql_destroy_many_to_many(model, f, style))
|
||||
|
||||
app_label = app_models[0]._meta.app_label
|
||||
|
||||
@@ -213,10 +127,10 @@ def sql_flush(style, only_django=False):
|
||||
"""
|
||||
from django.db import connection
|
||||
if only_django:
|
||||
tables = django_table_names()
|
||||
tables = connection.introspection.django_table_names()
|
||||
else:
|
||||
tables = table_names()
|
||||
statements = connection.ops.sql_flush(style, tables, sequence_list())
|
||||
tables = connection.introspection.table_names()
|
||||
statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
|
||||
return statements
|
||||
|
||||
def sql_custom(app, style):
|
||||
@@ -234,198 +148,16 @@ def sql_custom(app, style):
|
||||
|
||||
def sql_indexes(app, style):
|
||||
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
|
||||
from django.db import models
|
||||
from django.db import connection, models
|
||||
output = []
|
||||
for model in models.get_models(app):
|
||||
output.extend(sql_indexes_for_model(model, style))
|
||||
output.extend(connection.creation.sql_indexes_for_model(model, style))
|
||||
return output
|
||||
|
||||
def sql_all(app, style):
|
||||
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
||||
return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style)
|
||||
|
||||
def sql_model_create(model, style, known_models=set()):
|
||||
"""
|
||||
Returns the SQL required to create a single model, as a tuple of:
|
||||
(list_of_sql, pending_references_dict)
|
||||
"""
|
||||
from django.db import connection, models
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
table_output = []
|
||||
pending_references = {}
|
||||
qn = connection.ops.quote_name
|
||||
inline_references = connection.features.inline_fk_references
|
||||
for f in opts.local_fields:
|
||||
col_type = f.db_type()
|
||||
tablespace = f.db_tablespace or opts.db_tablespace
|
||||
if col_type is None:
|
||||
# Skip ManyToManyFields, because they're not represented as
|
||||
# database columns in this table.
|
||||
continue
|
||||
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
||||
field_output = [style.SQL_FIELD(qn(f.column)),
|
||||
style.SQL_COLTYPE(col_type)]
|
||||
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
||||
if f.primary_key:
|
||||
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
||||
elif f.unique:
|
||||
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
||||
if tablespace and connection.features.supports_tablespaces and f.unique:
|
||||
# We must specify the index tablespace inline, because we
|
||||
# won't be generating a CREATE INDEX statement for this field.
|
||||
field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
|
||||
if f.rel:
|
||||
if inline_references and f.rel.to in known_models:
|
||||
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
||||
style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
|
||||
style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
||||
connection.ops.deferrable_sql()
|
||||
)
|
||||
else:
|
||||
# We haven't yet created the table to which this field
|
||||
# is related, so save it for later.
|
||||
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
|
||||
table_output.append(' '.join(field_output))
|
||||
if opts.order_with_respect_to:
|
||||
table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
|
||||
style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
|
||||
style.SQL_KEYWORD('NULL'))
|
||||
for field_constraints in opts.unique_together:
|
||||
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
|
||||
", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
|
||||
|
||||
full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
|
||||
for i, line in enumerate(table_output): # Combine and add commas.
|
||||
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
||||
full_statement.append(')')
|
||||
if opts.db_tablespace and connection.features.supports_tablespaces:
|
||||
full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
|
||||
full_statement.append(';')
|
||||
final_output.append('\n'.join(full_statement))
|
||||
|
||||
if opts.has_auto_field:
|
||||
# Add any extra SQL needed to support auto-incrementing primary keys.
|
||||
auto_column = opts.auto_field.db_column or opts.auto_field.name
|
||||
autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
|
||||
if autoinc_sql:
|
||||
for stmt in autoinc_sql:
|
||||
final_output.append(stmt)
|
||||
|
||||
return final_output, pending_references
|
||||
|
||||
def sql_for_pending_references(model, style, pending_references):
|
||||
"""
|
||||
Returns any ALTER TABLE statements to add constraints after the fact.
|
||||
"""
|
||||
from django.db import connection
|
||||
from django.db.backends.util import truncate_name
|
||||
|
||||
qn = connection.ops.quote_name
|
||||
final_output = []
|
||||
if connection.features.supports_constraints:
|
||||
opts = model._meta
|
||||
if model in pending_references:
|
||||
for rel_class, f in pending_references[model]:
|
||||
rel_opts = rel_class._meta
|
||||
r_table = rel_opts.db_table
|
||||
r_col = f.column
|
||||
table = opts.db_table
|
||||
col = opts.get_field(f.rel.field_name).column
|
||||
# For MySQL, r_name must be unique in the first 64 characters.
|
||||
# So we are careful with character usage here.
|
||||
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
|
||||
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
|
||||
(qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
|
||||
qn(r_col), qn(table), qn(col),
|
||||
connection.ops.deferrable_sql()))
|
||||
del pending_references[model]
|
||||
return final_output
|
||||
|
||||
def many_to_many_sql_for_model(model, style):
|
||||
from django.db import connection, models
|
||||
from django.contrib.contenttypes import generic
|
||||
from django.db.backends.util import truncate_name
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
qn = connection.ops.quote_name
|
||||
inline_references = connection.features.inline_fk_references
|
||||
for f in opts.local_many_to_many:
|
||||
if f.creates_table:
|
||||
tablespace = f.db_tablespace or opts.db_tablespace
|
||||
if tablespace and connection.features.supports_tablespaces:
|
||||
tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
|
||||
else:
|
||||
tablespace_sql = ''
|
||||
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
|
||||
style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
|
||||
table_output.append(' %s %s %s%s,' %
|
||||
(style.SQL_FIELD(qn('id')),
|
||||
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
|
||||
tablespace_sql))
|
||||
if inline_references:
|
||||
deferred = []
|
||||
table_output.append(' %s %s %s %s (%s)%s,' %
|
||||
(style.SQL_FIELD(qn(f.m2m_column_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(qn(opts.db_table)),
|
||||
style.SQL_FIELD(qn(opts.pk.column)),
|
||||
connection.ops.deferrable_sql()))
|
||||
table_output.append(' %s %s %s %s (%s)%s,' %
|
||||
(style.SQL_FIELD(qn(f.m2m_reverse_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
|
||||
style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
|
||||
connection.ops.deferrable_sql()))
|
||||
else:
|
||||
table_output.append(' %s %s %s,' %
|
||||
(style.SQL_FIELD(qn(f.m2m_column_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL')))
|
||||
table_output.append(' %s %s %s,' %
|
||||
(style.SQL_FIELD(qn(f.m2m_reverse_name())),
|
||||
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL')))
|
||||
deferred = [
|
||||
(f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
|
||||
opts.pk.column),
|
||||
( f.m2m_db_table(), f.m2m_reverse_name(),
|
||||
f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
|
||||
]
|
||||
table_output.append(' %s (%s, %s)%s' %
|
||||
(style.SQL_KEYWORD('UNIQUE'),
|
||||
style.SQL_FIELD(qn(f.m2m_column_name())),
|
||||
style.SQL_FIELD(qn(f.m2m_reverse_name())),
|
||||
tablespace_sql))
|
||||
table_output.append(')')
|
||||
if opts.db_tablespace and connection.features.supports_tablespaces:
|
||||
# f.db_tablespace is only for indices, so ignore its value here.
|
||||
table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))
|
||||
table_output.append(';')
|
||||
final_output.append('\n'.join(table_output))
|
||||
|
||||
for r_table, r_col, table, col in deferred:
|
||||
r_name = '%s_refs_%s_%x' % (r_col, col,
|
||||
abs(hash((r_table, table))))
|
||||
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
|
||||
(qn(r_table),
|
||||
truncate_name(r_name, connection.ops.max_name_length()),
|
||||
qn(r_col), qn(table), qn(col),
|
||||
connection.ops.deferrable_sql()))
|
||||
|
||||
# Add any extra SQL needed to support auto-incrementing PKs
|
||||
autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
|
||||
if autoinc_sql:
|
||||
for stmt in autoinc_sql:
|
||||
final_output.append(stmt)
|
||||
|
||||
return final_output
|
||||
|
||||
def custom_sql_for_model(model, style):
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
@@ -461,28 +193,6 @@ def custom_sql_for_model(model, style):
|
||||
|
||||
return output
|
||||
|
||||
def sql_indexes_for_model(model, style):
|
||||
"Returns the CREATE INDEX SQL statements for a single model"
|
||||
from django.db import connection
|
||||
output = []
|
||||
|
||||
qn = connection.ops.quote_name
|
||||
for f in model._meta.local_fields:
|
||||
if f.db_index and not f.unique:
|
||||
tablespace = f.db_tablespace or model._meta.db_tablespace
|
||||
if tablespace and connection.features.supports_tablespaces:
|
||||
tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
|
||||
else:
|
||||
tablespace_sql = ''
|
||||
output.append(
|
||||
style.SQL_KEYWORD('CREATE INDEX') + ' ' + \
|
||||
style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
|
||||
style.SQL_KEYWORD('ON') + ' ' + \
|
||||
style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
|
||||
"(%s)" % style.SQL_FIELD(qn(f.column)) + \
|
||||
"%s;" % tablespace_sql
|
||||
)
|
||||
return output
|
||||
|
||||
def emit_post_sync_signal(created_models, verbosity, interactive):
|
||||
from django.db import models
|
||||
|
||||
@@ -61,11 +61,8 @@ def get_validation_errors(outfile, app=None):
|
||||
if f.db_index not in (None, True, False):
|
||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
||||
|
||||
# Check that max_length <= 255 if using older MySQL versions.
|
||||
if settings.DATABASE_ENGINE == 'mysql':
|
||||
db_version = connection.get_server_version()
|
||||
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
|
||||
e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
|
||||
# Perform any backend-specific field validation.
|
||||
connection.validation.validate_field(e, opts, f)
|
||||
|
||||
# Check to see if the related field will clash with any existing
|
||||
# fields, m2m fields, m2m related objects or related objects
|
||||
|
||||
Reference in New Issue
Block a user