Fixed #30444 -- Moved SQL generation for tables to BaseDatabaseSchemaEditor.table_sql().

This commit is contained in:
Rob Golding-Day 2019-05-05 16:26:06 -04:00 committed by Mariusz Felisiak
parent 0e2ed4fdd1
commit 4043dc69cd
2 changed files with 59 additions and 54 deletions

View File

@ -740,6 +740,7 @@ answer newbie questions, and generally made Django that much better:
Roberto Aguilar <roberto@baremetal.io>
Robert Rock Howard <http://djangomojo.com/>
Robert Wittams
Rob Golding-Day <rob@golding-day.com>
Rob Hudson <https://rob.cogit8.org/>
Robin Munn <http://www.geekforgod.com/>
Rodrigo Pinheiro Marques de Araújo <fenrrir@gmail.com>

View File

@ -140,6 +140,63 @@ class BaseDatabaseSchemaEditor:
def quote_name(self, name):
return self.connection.ops.quote_name(name)
def table_sql(self, model):
"""Take a model and return its table definition."""
# Add any unique_togethers (always deferred, as some fields might be
# created afterwards, like geometry fields with some backends).
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).column for field in fields]
self.deferred_sql.append(self._create_unique_sql(model, columns))
# Create column SQL, add FK deferreds if needed.
column_sqls = []
params = []
for field in model._meta.local_fields:
# SQL.
definition, extra_params = self.column_sql(model, field)
if definition is None:
continue
# Check constraints can go on the column SQL here.
db_params = field.db_parameters(connection=self.connection)
if db_params['check']:
definition += ' ' + self.sql_check_constraint % db_params
# Autoincrement SQL (for backends with inline variant).
col_type_suffix = field.db_type_suffix(connection=self.connection)
if col_type_suffix:
definition += ' %s' % col_type_suffix
params.extend(extra_params)
# FK.
if field.remote_field and field.db_constraint:
to_table = field.remote_field.model._meta.db_table
to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column
if self.sql_create_inline_fk:
definition += ' ' + self.sql_create_inline_fk % {
'to_table': self.quote_name(to_table),
'to_column': self.quote_name(to_column),
}
elif self.connection.features.supports_foreign_keys:
self.deferred_sql.append(self._create_fk_sql(model, field, '_fk_%(to_table)s_%(to_column)s'))
# Add the SQL to our big list.
column_sqls.append('%s %s' % (
self.quote_name(field.column),
definition,
))
# Autoincrement SQL (for backends with post table definition
# variant).
if field.get_internal_type() in ('AutoField', 'BigAutoField'):
autoinc_sql = self.connection.ops.autoinc_sql(model._meta.db_table, field.column)
if autoinc_sql:
self.deferred_sql.extend(autoinc_sql)
constraints = [constraint.constraint_sql(model, self) for constraint in model._meta.constraints]
sql = self.sql_create_table % {
'table': self.quote_name(model._meta.db_table),
'definition': ', '.join(constraint for constraint in (*column_sqls, *constraints) if constraint),
}
if model._meta.db_tablespace:
tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
if tablespace_sql:
sql += ' ' + tablespace_sql
return sql, params
# Field <-> database mapping functions
def column_sql(self, model, field, include_default=False):
@ -250,60 +307,7 @@ class BaseDatabaseSchemaEditor:
Create a table and any accompanying indexes or unique constraints for
the given `model`.
"""
# Create column SQL, add FK deferreds if needed
column_sqls = []
params = []
for field in model._meta.local_fields:
# SQL
definition, extra_params = self.column_sql(model, field)
if definition is None:
continue
# Check constraints can go on the column SQL here
db_params = field.db_parameters(connection=self.connection)
if db_params['check']:
definition += " " + self.sql_check_constraint % db_params
# Autoincrement SQL (for backends with inline variant)
col_type_suffix = field.db_type_suffix(connection=self.connection)
if col_type_suffix:
definition += " %s" % col_type_suffix
params.extend(extra_params)
# FK
if field.remote_field and field.db_constraint:
to_table = field.remote_field.model._meta.db_table
to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column
if self.sql_create_inline_fk:
definition += " " + self.sql_create_inline_fk % {
"to_table": self.quote_name(to_table),
"to_column": self.quote_name(to_column),
}
elif self.connection.features.supports_foreign_keys:
self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
# Add the SQL to our big list
column_sqls.append("%s %s" % (
self.quote_name(field.column),
definition,
))
# Autoincrement SQL (for backends with post table definition variant)
if field.get_internal_type() in ("AutoField", "BigAutoField"):
autoinc_sql = self.connection.ops.autoinc_sql(model._meta.db_table, field.column)
if autoinc_sql:
self.deferred_sql.extend(autoinc_sql)
# Add any unique_togethers (always deferred, as some fields might be
# created afterwards, like geometry fields with some backends)
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).column for field in fields]
self.deferred_sql.append(self._create_unique_sql(model, columns))
constraints = [constraint.constraint_sql(model, self) for constraint in model._meta.constraints]
# Make the table
sql = self.sql_create_table % {
"table": self.quote_name(model._meta.db_table),
"definition": ", ".join(constraint for constraint in (*column_sqls, *constraints) if constraint),
}
if model._meta.db_tablespace:
tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
if tablespace_sql:
sql += ' ' + tablespace_sql
sql, params = self.table_sql(model)
# Prevent using [] as params, in the case a literal '%' is used in the definition
self.execute(sql, params or None)