Exemple #1
0
def add_column(args, output):
    " <app> <model> <column> [<column2> ...]: Add one or more columns"
    if len(args) < 3:
        raise CommandError(
            './manage.py migration addcolumn <app> <model> <column> '
            '[<column2> ...]'
        )
    
    app_label, model, columns = args[0], args[1], args[2:]
    actual_model = models.get_model(app_label, model)
    
    style = no_style()
    sql, references = connection.creation.sql_create_model(
        actual_model, style, set()
    )
    
    col_specs = []
    for column in columns:
        is_foreign_key = isinstance(
            actual_model._meta.get_field_by_name(column)[0], models.ForeignKey
        )
        col_specs.append((
            column,
            extract_column_spec(sql[0], column, is_foreign_key),
            is_foreign_key
        ))
         
    migration_defs = [
        add_column_mtemplate % (app_label, model, column, col_spec)
        for (column, col_spec, is_foreign_key) in col_specs 
        if not is_foreign_key
    ]
    migration_fk_defs = [
      add_column_foreignkey_mtemplate % (
        app_label, model, column, col_spec,
        actual_model._meta.get_field_by_name(column)[0].rel.to._meta.db_table
      )
      for (column, col_spec, is_foreign_key) in col_specs 
      if is_foreign_key
    ]
    if migration_fk_defs:
        print >>sys.stderr, """Warning!
You have added columns that are foreign keys (%s).
These will be added as nullable. If you need them to be NOT NULL, then you
have to write another migration to do that, after you've populated them
with data.""" % ','.join([column for (column, x, fk) in col_specs if fk])
    
    migration_defs += migration_fk_defs
    migration_output = migration_code(*migration_defs)
    
    if len(columns) == 1:
        migration_name = 'add_column_%s_to_%s_%s' % (
            columns[0], app_label, model
        )
    else:
        migration_name = 'add_columns_%s_to_%s_%s' % (
            "_and_".join(columns), app_label, model
        )
    
    save_migration(output, migration_output, migration_name)
Exemple #2
0
def add_new(args, output):
    " <description>: Create empty migration (uses description in filename)"
    if not args:
        raise CommandError('./manage.py migration new <description>')

    db_engine = getattr(settings, 'DMIGRATIONS_DATABASE_BACKEND', 'mysql')

    save_migration(output, skeleton_template % db_engine,
                   '_'.join(args).lower())
Exemple #3
0
def add_new(args, output):
    " <description>: Create empty migration (uses description in filename)"
    if not args:
        raise CommandError('./manage.py migration new <description>')
    
    db_engine = getattr(settings, 'DMIGRATIONS_DATABASE_BACKEND', 'mysql')
    
    save_migration(
        output, skeleton_template % db_engine, '_'.join(args).lower()
    )
Exemple #4
0
def add_index(args, output):
    " <app> <model> <column>: Add an index"
    if len(args) != 3:
        raise CommandError(
            './manage.py migration addindex <app> <model> <column>')
    app_label, model, column = args

    migration_output = add_index_mtemplate % (app_label, model, column)
    migration_output = migration_code(migration_output)
    save_migration(output, migration_output,
                   'add_index_%s_%s_%s' % (app_label, model, column))
Exemple #5
0
def add_insert(args, output):
    " <app> <model>: Create insert migration for data in table"
    if len(args) != 2:
        raise CommandError('./manage.py migration insert <app> <model>')
    
    app_label, model = args
    table_name = '%s_%s' % (app_label, model)
    
    def get_columns(table_name):
        "Returns columns for table"
        cursor = connection.cursor()
        cursor.execute('describe %s' % table_name)
        rows = cursor.fetchall()
        cursor.close()

        # Sanity check that first column is called 'id' and is primary key
        first = rows[0]
        assert first[0] == u'id', 'First column must be id'
        assert first[3] == u'PRI', 'First column must be primary key'

        return [r[0] for r in rows]

    def get_dump(table_name):
        "Returns {'table_name':..., 'columns':..., 'rows':...}"
        columns = get_columns(table_name)
        # Escape column names with `backticks` - so columns with names that
        # match MySQL reserved words (e.g. "order") don't break things
        escaped_columns = ['`%s`' % column for column in columns]
        sql = 'SELECT %s FROM %s' % (', '.join(escaped_columns), table_name)

        cursor = connection.cursor()
        cursor.execute(sql)
        rows = cursor.fetchall()
        cursor.close()

        return {
            'table_name': table_name,
            'columns': columns,
            'rows': rows,
        }
    
    dump = get_dump(table_name)
    
    migration_output = insert_mtemplate % {
        'table_name': dump['table_name'],
        'columns': repr(dump['columns']),
        'insert_rows': pprint.pformat(dump['rows']),
        'delete_ids': ', '.join(map(str, [r[0] for r in dump['rows']])),
    }
    migration_output = migration_code(migration_output)
    
    save_migration(output, migration_output, 'insert_into_%s_%s' % (
        app_label, model
    ))
Exemple #6
0
def add_insert(args, output):
    " <app> <model>: Create insert migration for data in table"
    if len(args) != 2:
        raise CommandError('./manage.py migration insert <app> <model>')

    app_label, model = args
    table_name = '%s_%s' % (app_label, model)

    def get_columns(table_name):
        "Returns columns for table"
        cursor = connection.cursor()
        cursor.execute('describe %s' % table_name)
        rows = cursor.fetchall()
        cursor.close()

        # Sanity check that first column is called 'id' and is primary key
        first = rows[0]
        assert first[0] == u'id', 'First column must be id'
        assert first[3] == u'PRI', 'First column must be primary key'

        return [r[0] for r in rows]

    def get_dump(table_name):
        "Returns {'table_name':..., 'columns':..., 'rows':...}"
        columns = get_columns(table_name)
        # Escape column names with `backticks` - so columns with names that
        # match MySQL reserved words (e.g. "order") don't break things
        escaped_columns = ['`%s`' % column for column in columns]
        sql = 'SELECT %s FROM %s' % (', '.join(escaped_columns), table_name)

        cursor = connection.cursor()
        cursor.execute(sql)
        rows = cursor.fetchall()
        cursor.close()

        return {
            'table_name': table_name,
            'columns': columns,
            'rows': rows,
        }

    dump = get_dump(table_name)

    migration_output = insert_mtemplate % {
        'table_name': dump['table_name'],
        'columns': repr(dump['columns']),
        'insert_rows': pprint.pformat(dump['rows']),
        'delete_ids': ', '.join(map(str, [r[0] for r in dump['rows']])),
    }
    migration_output = migration_code(migration_output)

    save_migration(output, migration_output,
                   'insert_into_%s_%s' % (app_label, model))
Exemple #7
0
def add_index(args, output):
    " <app> <model> <column>: Add an index"
    if len(args) != 3:
        raise CommandError(
            './manage.py migration addindex <app> <model> <column>'
        )
    app_label, model, column = args
    
    migration_output = add_index_mtemplate % (app_label, model, column)
    migration_output = migration_code(migration_output)
    save_migration(output, migration_output, 'add_index_%s_%s_%s' % (
        app_label, model, column
    ))
Exemple #8
0
def add_column(args, output):
    " <app> <model> <column> [<column2> ...]: Add one or more columns"
    if len(args) < 3:
        raise CommandError(
            './manage.py migration addcolumn <app> <model> <column> '
            '[<column2> ...]')

    app_label, model, columns = args[0], args[1], args[2:]
    actual_model = models.get_model(app_label, model)

    style = no_style()
    sql, references = connection.creation.sql_create_model(
        actual_model, style, set())

    col_specs = []
    for column in columns:
        is_foreign_key = isinstance(
            actual_model._meta.get_field_by_name(column)[0], models.ForeignKey)
        col_specs.append(
            (column, extract_column_spec(sql[0], column,
                                         is_foreign_key), is_foreign_key))

    migration_defs = [
        add_column_mtemplate % (app_label, model, column, col_spec)
        for (column, col_spec, is_foreign_key) in col_specs
        if not is_foreign_key
    ]
    migration_fk_defs = [
        add_column_foreignkey_mtemplate %
        (app_label, model, column, col_spec,
         actual_model._meta.get_field_by_name(column)[0].rel.to._meta.db_table)
        for (column, col_spec, is_foreign_key) in col_specs if is_foreign_key
    ]
    if migration_fk_defs:
        print >> sys.stderr, """Warning!
You have added columns that are foreign keys (%s).
These will be added as nullable. If you need them to be NOT NULL, then you
have to write another migration to do that, after you've populated them
with data.""" % ','.join([column for (column, x, fk) in col_specs if fk])

    migration_defs += migration_fk_defs
    migration_output = migration_code(*migration_defs)

    if len(columns) == 1:
        migration_name = 'add_column_%s_to_%s_%s' % (columns[0], app_label,
                                                     model)
    else:
        migration_name = 'add_columns_%s_to_%s_%s' % ("_and_".join(columns),
                                                      app_label, model)

    save_migration(output, migration_output, migration_name)
Exemple #9
0
def add_app(args, output):
    " <app>: Add tables for a new application"
    if len(args) != 1:
        raise CommandError('./manage.py migration app <name-of-app>')
    app_label = args[0]
    app = models.get_app(app_label)
    from django.core.management.sql import sql_create

    up_sql = sql_create(app, no_style())
    down_sql = sql_delete(app, no_style())

    app_name = app.__name__.replace('.', '_')
    migration_output = app_mtemplate % (clean_up_create_sql(up_sql),
                                        clean_up_create_sql(down_sql))
    migration_output = migration_code(migration_output)

    save_migration(output, migration_output, app_name)
Exemple #10
0
def add_app(args, output):
    " <app>: Add tables for a new application"
    if len(args) != 1:
        raise CommandError('./manage.py migration app <name-of-app>')
    app_label = args[0]
    app = models.get_app(app_label)
    from django.core.management.sql import sql_create
    
    up_sql = sql_create(app, no_style())
    down_sql = sql_delete(app, no_style())
    
    app_name = app.__name__.replace('.', '_')
    migration_output = app_mtemplate % (
        clean_up_create_sql(up_sql), clean_up_create_sql(down_sql)
    )
    migration_output = migration_code(migration_output)
    
    save_migration(output, migration_output, app_name)
Exemple #11
0
def add_table(args, output):
    " <app> <model>: Add tables for a new model"
    if len(args) != 2:
        raise CommandError('./manage.py migration app <name-of-app>')
    app_label, model = args
    app = models.get_app(app_label)
    app_name = app.__name__.replace('.', '_')
    model_to_add = models.get_model(app_label, model)

    if not model_to_add:
        raise Exception("Model %s in app %s not found" % (model, app_label))

    # The following code is a bit of a mess. I copied it from
    # django.core.management.sql.sql_create without a full understanding of
    # how it all works. Ideally this needs to refactored in Django itself to
    # make it easier for libraries such as this one to reuse the table
    # creation logic.
    style = no_style()
    app_models = models.get_models(app)
    up_sql = []
    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 = {}

    sql_output, references = connection.creation.sql_create_model(
        model_to_add, style, known_models)
    up_sql.extend(sql_output)
    for refto, refs in references.items():
        pending_references.setdefault(refto, []).extend(refs)
        if refto in known_models:
            up_sql.extend(
                connection.creation.sql_for_pending_references(
                    refto, style, pending_references))
    up_sql.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_to_add)

    # Create the many-to-many join tables.
    up_sql.extend(connection.creation.sql_for_many_to_many(
        model_to_add, style))
    if not up_sql:
        raise Exception("Model %s in app %s not found" % (model, app_label))

    # Down sql just drops any tables we have created
    down_sql = []
    for sql in up_sql:
        if sql.startswith('CREATE TABLE'):
            down_sql.append('DROP TABLE %s;' % sql.split()[2])

    # Reverse the order of down_sql
    down_sql = down_sql[::-1]

    migration_output = app_mtemplate % (clean_up_create_sql(up_sql),
                                        clean_up_create_sql(down_sql))
    migration_output = migration_code(migration_output)

    save_migration(output, migration_output, app_name)
Exemple #12
0
def add_table(args, output):
    " <app> <model>: Add tables for a new model"
    if len(args) != 2:
        raise CommandError('./manage.py migration app <name-of-app>')
    app_label, model = args
    app = models.get_app(app_label)
    app_name = app.__name__.replace('.', '_')
    model_to_add = models.get_model(app_label, model)
    
    if not model_to_add:
        raise Exception("Model %s in app %s not found" % (model, app_label))
    
    # The following code is a bit of a mess. I copied it from 
    # django.core.management.sql.sql_create without a full understanding of 
    # how it all works. Ideally this needs to refactored in Django itself to 
    # make it easier for libraries such as this one to reuse the table 
    # creation logic.
    style = no_style()
    app_models = models.get_models(app)
    up_sql = []
    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 = {}

    sql_output, references = connection.creation.sql_create_model(
        model_to_add, style, known_models
    )
    up_sql.extend(sql_output)
    for refto, refs in references.items():
        pending_references.setdefault(refto, []).extend(refs)
        if refto in known_models:
            up_sql.extend(
                connection.creation.sql_for_pending_references(
                    refto, style, pending_references
                )
            )
    up_sql.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_to_add)

    # Create the many-to-many join tables.
    up_sql.extend(
        connection.creation.sql_for_many_to_many(model_to_add, style)
    )
    if not up_sql:
        raise Exception("Model %s in app %s not found" % (model, app_label))
    
    # Down sql just drops any tables we have created
    down_sql = []
    for sql in up_sql:
        if sql.startswith('CREATE TABLE'):
            down_sql.append('DROP TABLE %s;' % sql.split()[2])
    
    # Reverse the order of down_sql
    down_sql = down_sql[::-1]
    
    migration_output = app_mtemplate % (
        clean_up_create_sql(up_sql), clean_up_create_sql(down_sql)
    )
    migration_output = migration_code(migration_output)
    
    save_migration(output, migration_output, app_name)