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
                    )
                )
Example #2
0
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))
Example #3
0
    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))
Example #4
0
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
                    )
                )