def rename_column(self, model, old_field, new_field): if old_field.column == new_field.column: # No Operation return [] qn = self.connection.ops.quote_name max_name_length = self.connection.ops.max_name_length() sql_result = AlterTableSQLResult(self, model) pre_sql, stash = self.stash_field_ref_constraints(model=model, replaced_fields={ old_field: new_field, }) sql_result.add_pre_sql(pre_sql) sql_result.add_alter_table([{ 'independent': True, 'sql': 'RENAME COLUMN %s TO %s' % (truncate_name(qn(old_field.column), max_name_length), truncate_name(qn(new_field.column), max_name_length)), }]) sql_result.add_post_sql(self.restore_field_ref_constraints(stash)) return sql_result
def add_column(self, model, f, initial): qn = self.connection.ops.quote_name sql_result = AlterTableSQLResult(self, model) if f.rel: # it is a foreign key field # NOT NULL REFERENCES "django_evolution_addbasemodel" # ("id") DEFERRABLE INITIALLY DEFERRED # ALTER TABLE <tablename> ADD COLUMN <column name> NULL # REFERENCES <tablename1> ("<colname>") DEFERRABLE INITIALLY # DEFERRED related_model = f.rel.to related_table = related_model._meta.db_table related_pk_col = related_model._meta.pk.name constraints = ['%sNULL' % (not f.null and 'NOT ' or '')] if f.unique or f.primary_key: constraints.append('UNIQUE') sql_result.add_alter_table([ { 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': constraints + [ 'REFERENCES', qn(related_table), '(%s)' % qn(related_pk_col), self.connection.ops.deferrable_sql(), ] } ]) else: null_constraints = '%sNULL' % (not f.null and 'NOT ' or '') if f.unique or f.primary_key: unique_constraints = 'UNIQUE' else: unique_constraints = '' # At this point, initial can only be None if null=True, # otherwise it is a user callable or the default # AddFieldInitialCallback which will shortly raise an exception. if initial is not None: if callable(initial): sql_result.add_alter_table([ { 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [unique_constraints], } ]) sql_result.add_sql([ 'UPDATE %s SET %s = %s WHERE %s IS NULL;' % (qn(model._meta.db_table), qn(f.column), initial(), qn(f.column)) ]) if not f.null: # Only put this sql statement if the column cannot # be null. sql_result.add_sql( self.set_field_null(model, f, f.null)) else: sql_result.add_alter_table([ { 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [ null_constraints, unique_constraints, 'DEFAULT', '%s', ], 'sql_params': [initial] } ]) # Django doesn't generate default columns, so now that # we've added one to get default values for existing # tables, drop that default. sql_result.add_post_sql([ 'ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT;' % (qn(model._meta.db_table), qn(f.column)) ]) else: sql_result.add_alter_table([ { 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [null_constraints, unique_constraints], } ]) if f.unique or f.primary_key: self.record_index(model, [f], use_constraint_name=True, unique=True) return sql_result
def get_change_column_type_sql(self, model, old_field, new_field): """Return SQL to change the type of a column. Version Added: 2.2 Args: model (type): The type of model owning the field. old_field (django.db.models.Field): The old field. new_field (django.db.models.Field): The new field. Returns: django_evolution.sql_result.AlterTableSQLResult: The SQL statements for changing the column type. """ connection = self.connection qn = connection.ops.quote_name schema = self.build_column_schema( model=model, field=new_field, initial=new_field.default, skip_null_constraint=True, skip_primary_or_unique_constraint=True, skip_references=True) column_name = schema['name'] table_name = model._meta.db_table sql_result = AlterTableSQLResult(self, model) old_field_type = old_field.db_type(connection=connection).lower() new_field_type = schema['db_type'].lower() was_serial = old_field_type in self.alter_field_type_map is_serial = new_field_type in self.alter_field_type_map if is_serial: # This is a serial field. We will need to change the type and # update the sequence. We will also need to choose the actual # type to set for the column definition. new_field_type = self.alter_field_type_map.get( new_field_type, new_field_type) alter_type_params = ['TYPE', new_field_type] + schema['definition'] if not self._are_column_types_compatible(old_field, new_field): alter_type_params += [ 'USING', '%s::%s' % (column_name, new_field_type), ] sql_result.add_alter_table([{ 'op': 'ALTER COLUMN', 'column': column_name, 'params': alter_type_params, 'sql_params': schema['definition_sql_params'], }]) if is_serial: # Reset the sequence. sequence_name = '%s_%s_seq' % (table_name, column_name) sequence_sql_result = AlterTableSQLResult(self, model) sequence_sql_result.add_pre_sql([ 'DROP SEQUENCE IF EXISTS %s CASCADE;' % qn(sequence_name), 'CREATE SEQUENCE %s;' % qn(sequence_name), ]) sequence_sql_result.add_alter_table([{ 'op': 'ALTER COLUMN', 'column': column_name, 'params': [ 'SET', 'DEFAULT', "nextval('%s')" % qn(sequence_name), ], }]) sequence_sql_result.add_post_sql([ "SELECT setval('%s', MAX(%s)) FROM %s;" % (qn(sequence_name), qn(column_name), qn(table_name)), 'ALTER SEQUENCE %s OWNED BY %s.%s;' % (qn(sequence_name), qn(table_name), qn(column_name)), ]) sql_result.add_post_sql(sequence_sql_result) elif was_serial: # Drop the old sequence, since we no longer need it. sequence_name = '%s_%s_seq' % (table_name, old_field.column) sql_result.add_post_sql([ 'DROP SEQUENCE IF EXISTS %s CASCADE;' % qn(sequence_name), ]) return sql_result
def add_column(self, model, f, initial): qn = self.connection.ops.quote_name sql_result = AlterTableSQLResult(self, model) if f.rel: # it is a foreign key field # NOT NULL REFERENCES "django_evolution_addbasemodel" # ("id") DEFERRABLE INITIALLY DEFERRED # ALTER TABLE <tablename> ADD COLUMN <column name> NULL # REFERENCES <tablename1> ("<colname>") DEFERRABLE INITIALLY # DEFERRED related_model = f.rel.to related_table = related_model._meta.db_table related_pk_col = related_model._meta.pk.name constraints = ['%sNULL' % (not f.null and 'NOT ' or '')] if f.unique or f.primary_key: constraints.append('UNIQUE') sql_result.add_alter_table([{ 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': constraints + [ 'REFERENCES', qn(related_table), '(%s)' % qn(related_pk_col), self.connection.ops.deferrable_sql(), ] }]) else: null_constraints = '%sNULL' % (not f.null and 'NOT ' or '') if f.unique or f.primary_key: unique_constraints = 'UNIQUE' else: unique_constraints = '' # At this point, initial can only be None if null=True, # otherwise it is a user callable or the default # AddFieldInitialCallback which will shortly raise an exception. if initial is not None: if callable(initial): sql_result.add_alter_table([{ 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [unique_constraints], }]) sql_result.add_sql([ 'UPDATE %s SET %s = %s WHERE %s IS NULL;' % (qn(model._meta.db_table), qn( f.column), initial(), qn(f.column)) ]) if not f.null: # Only put this sql statement if the column cannot # be null. sql_result.add_sql( self.set_field_null(model, f, f.null)) else: sql_result.add_alter_table([{ 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [ null_constraints, unique_constraints, 'DEFAULT', '%s', ], 'sql_params': [initial] }]) # Django doesn't generate default columns, so now that # we've added one to get default values for existing # tables, drop that default. sql_result.add_post_sql([ 'ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT;' % (qn(model._meta.db_table), qn(f.column)) ]) else: sql_result.add_alter_table([{ 'op': 'ADD COLUMN', 'column': f.column, 'db_type': f.db_type(connection=self.connection), 'params': [null_constraints, unique_constraints], }]) if f.unique or f.primary_key: self.record_index(model, [f], use_constraint_name=True, unique=True) return sql_result
def rename_column(self, model, old_field, new_field): """Rename the specified column. This will rename the column through ``ALTER TABLE .. CHANGE COLUMN``. Any constraints on the column will be stashed away before the ``ALTER TABLE`` and restored afterward. If the column has not actually changed, or it's not a real column (a many-to-many relation), then this will return empty statements. Args: model (type): The model representing the table containing the column. old_field (django.db.models.Field): The old field definition. new_field (django.db.models.Field): The new field definition. Returns: django_evolution.db.sql_result.AlterTableSQLResult or list: The statements for renaming the column. This may be an empty list if the column won't be renamed. """ if old_field.column == new_field.column: # No Operation return [] col_type = new_field.db_type(connection=self.connection) if col_type is None: # Skip ManyToManyFields, because they're not represented as # database columns in this table. return [] qn = self.connection.ops.quote_name sql_result = AlterTableSQLResult(self, model) pre_sql, stash = self.stash_field_ref_constraints( model=model, replaced_fields={ old_field: new_field, }) sql_result.add_pre_sql(pre_sql) schema = self.build_column_schema(model=model, field=new_field, initial=new_field.default) alter_table_items = [] if old_field.primary_key: alter_table_items.append('DROP PRIMARY KEY') alter_table_items.append( 'CHANGE COLUMN %s %s' % (qn(old_field.column), ' '.join([ qn(schema['name']), schema['db_type'], ] + schema['definition']))) sql_result.add_alter_table([{ 'sql': ', '.join(alter_table_items), }]) sql_result.add_post_sql(self.restore_field_ref_constraints(stash)) return sql_result