def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): """ Alters the given column name so it will match the given field. Note that conversion between the two by the database must be possible. Will not automatically add _id by default; to have this behavour, pass explicit_name=False. @param table_name: The name of the table to add the column to @param name: The name of the column to alter @param field: The new field definition to use """ if self.dry_run: if self.debug: print(' - no dry run output for alter_column() due to dynamic DDL, sorry') return # hook for the field to do any resolution prior to it's attributes being queried if hasattr(field, 'south_init'): field.south_init() # Add _id or whatever if we need to field.set_attributes_from_name(name) if not explicit_name: name = field.column else: field.column = name if not ignore_constraints: # Drop all check constraints. Note that constraints will be added back # with self.alter_string_set_type and self.alter_string_drop_null. self._drop_constraints(table_name, name, field) # First, change the type params = { "column": self.quote_name(name), "type": self._db_type_for_alter_column(field), "table_name": table_name } # SQLs is a list of (SQL, values) pairs. sqls = [] sqls_extra = [] # Only alter the column if it has a type (Geometry ones sometimes don't) if params["type"] is not None: sqls.append((self.alter_string_set_type % params, [])) # Add any field- and backend- specific modifications self._alter_add_column_mods(field, name, params, sqls) # Next, nullity: modified, firebird doesn't support DROP NOT NULL sqls_extra.append(self._alter_column_set_null(table_name, name, field.null)) # Next, set any default self._alter_set_defaults(field, name, params, sqls) # Finally, actually change the column if self.allows_combined_alters: sqls, values = list(zip(*sqls)) self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), generic.flatten(values), ) else: # Databases like e.g. MySQL don't like more than one alter at once. for sql, values in sqls: try: self.execute("ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) except DatabaseError as e: print(e) # Execute extra sql, which don't need ALTER TABLE statement for sql in sqls_extra: self.execute(sql) if not ignore_constraints: # Add back FK constraints if needed if field.rel and self.supports_foreign_keys: self.execute( self.foreign_key_sql( table_name, field.column, field.rel.to._meta.db_table, field.rel.to._meta.get_field(field.rel.field_name).column ) )
def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): """ Alters the given column name so it will match the given field. Note that conversion between the two by the database must be possible. Will not automatically add _id by default; to have this behavour, pass explicit_name=False. @param table_name: The name of the table to add the column to @param name: The name of the column to alter @param field: The new field definition to use """ if self.dry_run: if self.debug: print ' - no dry run output for alter_column() due to dynamic DDL, sorry' return # hook for the field to do any resolution prior to it's attributes being queried if hasattr(field, 'south_init'): field.south_init() # Add _id or whatever if we need to field.set_attributes_from_name(name) if not explicit_name: name = field.column else: field.column = name if not ignore_constraints: # Drop all check constraints. Note that constraints will be added back # with self.alter_string_set_type and self.alter_string_drop_null. if self.has_check_constraints: check_constraints = self._constraints_affecting_columns( table_name, [name], "CHECK") for constraint in check_constraints: self.execute( self.delete_check_sql % { 'table': self.quote_name(table_name), 'constraint': self.quote_name(constraint), }) # Drop or add UNIQUE constraint unique_constraint = list( self._constraints_affecting_columns(table_name, [name], "UNIQUE")) if field.unique and not unique_constraint: self.create_unique(table_name, [name]) elif not field.unique and unique_constraint: self.delete_unique(table_name, [name]) # Drop all foreign key constraints try: self.delete_foreign_key(table_name, name) except ValueError: # There weren't any pass # First, change the type params = { "column": self.quote_name(name), "type": self._db_type_for_alter_column(field), "table_name": table_name } # SQLs is a list of (SQL, values) pairs. sqls = [] # Only alter the column if it has a type (Geometry ones sometimes don't) if params["type"] is not None: sqls.append((self.alter_string_set_type % params, [])) # Add any field- and backend- specific modifications self._alter_add_column_mods(field, name, params, sqls) # Next, nullity if field.null: sqls.append((self.alter_string_set_null % params, [])) else: sqls.append((self.alter_string_drop_null % params, [])) # Next, set any default self._alter_set_defaults(field, name, params, sqls) # Finally, actually change the column if self.allows_combined_alters: sqls, values = zip(*sqls) self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), flatten(values), ) else: # Databases like e.g. MySQL don't like more than one alter at once. for sql, values in sqls: self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) if not ignore_constraints: # Add back FK constraints if needed if field.rel and self.supports_foreign_keys: # HACK: "soft" FK handling begin if not hasattr(field, 'no_db_constraints') or not field.no_db_constraints: self.execute( self.foreign_key_sql( table_name, field.column, field.rel.to._meta.db_table, field.rel.to._meta.get_field( field.rel.field_name).column))
def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): """ Alters the given column name so it will match the given field. Note that conversion between the two by the database must be possible. Will not automatically add _id by default; to have this behavour, pass explicit_name=False. @param table_name: The name of the table to add the column to @param name: The name of the column to alter @param field: The new field definition to use """ if self.dry_run: if self.debug: print( ' - no dry run output for alter_column() due to dynamic DDL, sorry' ) return # hook for the field to do any resolution prior to it's attributes being queried if hasattr(field, 'south_init'): field.south_init() # Add _id or whatever if we need to field.set_attributes_from_name(name) if not explicit_name: name = field.column else: field.column = name if not ignore_constraints: # Drop all check constraints. Note that constraints will be added back # with self.alter_string_set_type and self.alter_string_drop_null. self._drop_constraints(table_name, name, field) # First, change the type params = { "column": self.quote_name(name), "type": self._db_type_for_alter_column(field), "table_name": table_name } # SQLs is a list of (SQL, values) pairs. sqls = [] sqls_extra = [] # Only alter the column if it has a type (Geometry ones sometimes don't) if params["type"] is not None: sqls.append((self.alter_string_set_type % params, [])) # Add any field- and backend- specific modifications self._alter_add_column_mods(field, name, params, sqls) # Next, nullity: modified, firebird doesn't support DROP NOT NULL sqls_extra.append( self._alter_column_set_null(table_name, name, field.null)) # Next, set any default self._alter_set_defaults(field, name, params, sqls) # Finally, actually change the column if self.allows_combined_alters: sqls, values = list(zip(*sqls)) self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), generic.flatten(values), ) else: # Databases like e.g. MySQL don't like more than one alter at once. for sql, values in sqls: try: self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) except DatabaseError as e: print(e) # Execute extra sql, which don't need ALTER TABLE statement for sql in sqls_extra: self.execute(sql) if not ignore_constraints: # Add back FK constraints if needed if field.rel and self.supports_foreign_keys: self.execute( self.foreign_key_sql( table_name, field.column, field.rel.to._meta.db_table, field.rel.to._meta.get_field( field.rel.field_name).column))
def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): """ Alters the given column name so it will match the given field. Note that conversion between the two by the database must be possible. Will not automatically add _id by default; to have this behavour, pass explicit_name=False. @param table_name: The name of the table to add the column to @param name: The name of the column to alter @param field: The new field definition to use """ if self.dry_run: if self.debug: print ' - no dry run output for alter_column() due to dynamic DDL, sorry' return # hook for the field to do any resolution prior to it's attributes being queried if hasattr(field, 'south_init'): field.south_init() # Add _id or whatever if we need to field.set_attributes_from_name(name) if not explicit_name: name = field.column else: field.column = name if not ignore_constraints: # Drop all check constraints. Note that constraints will be added back # with self.alter_string_set_type and self.alter_string_drop_null. if self.has_check_constraints: check_constraints = self._constraints_affecting_columns(table_name, [name], "CHECK") for constraint in check_constraints: self.execute(self.delete_check_sql % { 'table': self.quote_name(table_name), 'constraint': self.quote_name(constraint), }) # Drop or add UNIQUE constraint unique_constraint = list(self._constraints_affecting_columns(table_name, [name], "UNIQUE")) if field.unique and not unique_constraint: self.create_unique(table_name, [name]) elif not field.unique and unique_constraint: self.delete_unique(table_name, [name]) # Drop all foreign key constraints try: self.delete_foreign_key(table_name, name) except ValueError: # There weren't any pass # First, change the type params = { "column": self.quote_name(name), "type": self._db_type_for_alter_column(field), "table_name": table_name } # SQLs is a list of (SQL, values) pairs. sqls = [] # Only alter the column if it has a type (Geometry ones sometimes don't) if params["type"] is not None: sqls.append((self.alter_string_set_type % params, [])) # Add any field- and backend- specific modifications self._alter_add_column_mods(field, name, params, sqls) # Next, nullity if field.null: sqls.append((self.alter_string_set_null % params, [])) else: sqls.append((self.alter_string_drop_null % params, [])) # Next, set any default self._alter_set_defaults(field, name, params, sqls) # Finally, actually change the column if self.allows_combined_alters: sqls, values = zip(*sqls) self.execute( "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), flatten(values), ) else: # Databases like e.g. MySQL don't like more than one alter at once. for sql, values in sqls: self.execute("ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) if not ignore_constraints: # Add back FK constraints if needed if field.rel and self.supports_foreign_keys: # HACK: "soft" FK handling begin if not hasattr(field, 'no_db_constraints') or not field.no_db_constraints: self.execute( self.foreign_key_sql( table_name, field.column, field.rel.to._meta.db_table, field.rel.to._meta.get_field(field.rel.field_name).column ) )