from alembic.migration import MigrationContext
from alembic.autogenerate import compare_metadata
- from sqlalchemy.schema import SchemaItem
- from sqlalchemy.types import TypeEngine
- from sqlalchemy import (create_engine, MetaData, Column,
- Integer, String, Table, text)
+ from sqlalchemy import (
+ create_engine,
+ MetaData,
+ Column,
+ Integer,
+ String,
+ Table,
+ text,
+ )
import pprint
engine = create_engine("sqlite://")
with engine.begin() as conn:
- conn.execute(text('''
- create table foo (
- id integer not null primary key,
- old_data varchar,
- x integer
- )'''))
-
- conn.execute(text('''
- create table bar (
- data varchar
- )'''))
+ conn.execute(
+ text(
+ '''
+ create table foo (
+ id integer not null primary key,
+ old_data varchar,
+ x integer
+ )
+ '''
+ )
+ )
+ conn.execute(text("create table bar (data varchar)"))
metadata = MetaData()
- Table('foo', metadata,
- Column('id', Integer, primary_key=True),
- Column('data', Integer),
- Column('x', Integer, nullable=False)
- )
- Table('bat', metadata,
- Column('info', String)
+ Table(
+ "foo",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("data", Integer),
+ Column("x", Integer, nullable=False),
)
+ Table("bat", metadata, Column("info", String))
mc = MigrationContext.configure(engine.connect())
Output::
- [ ( 'add_table',
- Table('bat', MetaData(bind=None),
- Column('info', String(), table=<bat>), schema=None)),
- ( 'remove_table',
- Table(u'bar', MetaData(bind=None),
- Column(u'data', VARCHAR(), table=<bar>), schema=None)),
- ( 'add_column',
- None,
- 'foo',
- Column('data', Integer(), table=<foo>)),
- ( 'remove_column',
- None,
- 'foo',
- Column(u'old_data', VARCHAR(), table=None)),
- [ ( 'modify_nullable',
- None,
- 'foo',
- u'x',
- { 'existing_server_default': None,
- 'existing_type': INTEGER()},
- True,
- False)]]
-
+ [
+ (
+ "add_table",
+ Table(
+ "bat",
+ MetaData(),
+ Column("info", String(), table=<bat>),
+ schema=None,
+ ),
+ ),
+ (
+ "remove_table",
+ Table(
+ "bar",
+ MetaData(),
+ Column("data", VARCHAR(), table=<bar>),
+ schema=None,
+ ),
+ ),
+ (
+ "add_column",
+ None,
+ "foo",
+ Column("data", Integer(), table=<foo>),
+ ),
+ [
+ (
+ "modify_nullable",
+ None,
+ "foo",
+ "x",
+ {
+ "existing_comment": None,
+ "existing_server_default": False,
+ "existing_type": INTEGER(),
+ },
+ True,
+ False,
+ )
+ ],
+ (
+ "remove_column",
+ None,
+ "foo",
+ Column("old_data", VARCHAR(), table=<foo>),
+ ),
+ ]
:param context: a :class:`.MigrationContext`
instance.
writer1 = autogenerate.Rewriter()
writer2 = autogenerate.Rewriter()
+
@writer1.rewrites(ops.AddColumnOp)
def add_column_nullable(context, revision, op):
op.column.nullable = True
return op
+
@writer2.rewrites(ops.AddColumnOp)
def add_column_idx(context, revision, op):
idx_op = ops.CreateIndexOp(
- 'ixc', op.table_name, [op.column.name])
- return [
- op,
- idx_op
- ]
+ "ixc", op.table_name, [op.column.name]
+ )
+ return [op, idx_op]
writer = writer1.chain(writer2)
op.create_exclude_constraint(
"user_excl",
"user",
-
- ("period", '&&'),
- ("group", '='),
- where=("group != 'some group'")
-
+ ("period", "&&"),
+ ("group", "="),
+ where=("group != 'some group'"),
)
Note that the expressions work the same way as that of
from alembic import op
from sqlalchemy import Column, String
- op.add_column('organization',
- Column('name', String())
- )
+ op.add_column("organization", Column("name", String()))
The provided :class:`~sqlalchemy.schema.Column` object can also
specify a :class:`~sqlalchemy.schema.ForeignKey`, referencing
from alembic import op
from sqlalchemy import Column, INTEGER, ForeignKey
- op.add_column('organization',
- Column('account_id', INTEGER, ForeignKey('accounts.id'))
+ op.add_column(
+ "organization",
+ Column("account_id", INTEGER, ForeignKey("accounts.id")),
)
Note that this statement uses the :class:`~sqlalchemy.schema.Column`
from sqlalchemy import Column, TIMESTAMP, func
# specify "DEFAULT NOW" along with the column add
- op.add_column('account',
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ op.add_column(
+ "account",
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
:param table_name: String name of the parent table.
are omitted. E.g.::
with op.batch_alter_table("some_table") as batch_op:
- batch_op.add_column(Column('foo', Integer))
- batch_op.drop_column('bar')
+ batch_op.add_column(Column("foo", Integer))
+ batch_op.drop_column("bar")
The operations within the context manager are invoked at once
when the context is ended. When run against SQLite, if the
Specify the order of all columns::
with op.batch_alter_table(
- "some_table", recreate="always",
- partial_reordering=[("c", "d", "a", "b")]
+ "some_table",
+ recreate="always",
+ partial_reordering=[("c", "d", "a", "b")],
) as batch_op:
pass
Ensure "d" appears before "c", and "b", appears before "a"::
with op.batch_alter_table(
- "some_table", recreate="always",
- partial_reordering=[("d", "c"), ("b", "a")]
+ "some_table",
+ recreate="always",
+ partial_reordering=[("d", "c"), ("b", "a")],
) as batch_op:
pass
from sqlalchemy import String, Integer, Date
# Create an ad-hoc table to use for the insert statement.
- accounts_table = table('account',
- column('id', Integer),
- column('name', String),
- column('create_date', Date)
+ accounts_table = table(
+ "account",
+ column("id", Integer),
+ column("name", String),
+ column("create_date", Date),
)
- op.bulk_insert(accounts_table,
+ op.bulk_insert(
+ accounts_table,
[
- {'id':1, 'name':'John Smith',
- 'create_date':date(2010, 10, 5)},
- {'id':2, 'name':'Ed Williams',
- 'create_date':date(2007, 5, 27)},
- {'id':3, 'name':'Wendy Jones',
- 'create_date':date(2008, 8, 15)},
- ]
+ {
+ "id": 1,
+ "name": "John Smith",
+ "create_date": date(2010, 10, 5),
+ },
+ {
+ "id": 2,
+ "name": "Ed Williams",
+ "create_date": date(2007, 5, 27),
+ },
+ {
+ "id": 3,
+ "name": "Wendy Jones",
+ "create_date": date(2008, 8, 15),
+ },
+ ],
)
When using --sql mode, some datatypes may not render inline
automatically, such as dates and other special types. When this
issue is present, :meth:`.Operations.inline_literal` may be used::
- op.bulk_insert(accounts_table,
+ op.bulk_insert(
+ accounts_table,
[
- {'id':1, 'name':'John Smith',
- 'create_date':op.inline_literal("2010-10-05")},
- {'id':2, 'name':'Ed Williams',
- 'create_date':op.inline_literal("2007-05-27")},
- {'id':3, 'name':'Wendy Jones',
- 'create_date':op.inline_literal("2008-08-15")},
+ {
+ "id": 1,
+ "name": "John Smith",
+ "create_date": op.inline_literal("2010-10-05"),
+ },
+ {
+ "id": 2,
+ "name": "Ed Williams",
+ "create_date": op.inline_literal("2007-05-27"),
+ },
+ {
+ "id": 3,
+ "name": "Wendy Jones",
+ "create_date": op.inline_literal("2008-08-15"),
+ },
],
- multiinsert=False
+ multiinsert=False,
)
When using :meth:`.Operations.inline_literal` in conjunction with
op.create_check_constraint(
"ck_user_name_len",
"user",
- func.len(column('name')) > 5
+ func.len(column("name")) > 5,
)
CHECK constraints are usually against a SQL expression, so ad-hoc
op.create_exclude_constraint(
"user_excl",
"user",
-
- ("period", '&&'),
- ("group", '='),
- where=("group != 'some group'")
-
+ ("period", "&&"),
+ ("group", "="),
+ where=("group != 'some group'"),
)
Note that the expressions work the same way as that of
e.g.::
from alembic import op
+
op.create_foreign_key(
- "fk_user_address", "address",
- "user", ["user_id"], ["id"])
+ "fk_user_address",
+ "address",
+ "user",
+ ["user_id"],
+ ["id"],
+ )
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
e.g.::
from alembic import op
- op.create_index('ik_test', 't1', ['foo', 'bar'])
+
+ op.create_index("ik_test", "t1", ["foo", "bar"])
Functional indexes can be produced by using the
:func:`sqlalchemy.sql.expression.text` construct::
from alembic import op
from sqlalchemy import text
- op.create_index('ik_test', 't1', [text('lower(foo)')])
+
+ op.create_index("ik_test", "t1", [text("lower(foo)")])
:param index_name: name of the index.
:param table_name: name of the owning table.
e.g.::
from alembic import op
+
op.create_primary_key(
- "pk_my_table", "my_table",
- ["id", "version"]
- )
+ "pk_my_table", "my_table", ["id", "version"]
+ )
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
from alembic import op
op.create_table(
- 'account',
- Column('id', INTEGER, primary_key=True),
- Column('name', VARCHAR(50), nullable=False),
- Column('description', NVARCHAR(200)),
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ "account",
+ Column("id", INTEGER, primary_key=True),
+ Column("name", VARCHAR(50), nullable=False),
+ Column("description", NVARCHAR(200)),
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
Note that :meth:`.create_table` accepts
from alembic import op
account_table = op.create_table(
- 'account',
- Column('id', INTEGER, primary_key=True),
- Column('name', VARCHAR(50), nullable=False),
- Column('description', NVARCHAR(200)),
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ "account",
+ Column("id", INTEGER, primary_key=True),
+ Column("name", VARCHAR(50), nullable=False),
+ Column("description", NVARCHAR(200)),
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
op.bulk_insert(
[
{"name": "A1", "description": "account 1"},
{"name": "A2", "description": "account 2"},
- ]
+ ],
)
:param table_name: Name of the table
e.g.::
- drop_column('organization', 'account_id')
+ drop_column("organization", "account_id")
:param table_name: name of table
:param column_name: name of column
If the :meth:`.Operations.f` is used on a constraint, the naming
convention will not take effect::
- op.add_column('t', 'x', Boolean(name=op.f('ck_bool_t_x')))
+ op.add_column("t", "x", Boolean(name=op.f("ck_bool_t_x")))
Above, the CHECK constraint generated will have the name
``ck_bool_t_x`` regardless of whether or not a naming convention is
``{"ck": "ck_bool_%(table_name)s_%(constraint_name)s"}``, then the
output of the following:
- op.add_column('t', 'x', Boolean(name='x'))
+ op.add_column("t", "x", Boolean(name="x"))
will be::
are omitted. E.g.::
with op.batch_alter_table("some_table") as batch_op:
- batch_op.add_column(Column('foo', Integer))
- batch_op.drop_column('bar')
+ batch_op.add_column(Column("foo", Integer))
+ batch_op.drop_column("bar")
The operations within the context manager are invoked at once
when the context is ended. When run against SQLite, if the
Specify the order of all columns::
with op.batch_alter_table(
- "some_table", recreate="always",
- partial_reordering=[("c", "d", "a", "b")]
+ "some_table",
+ recreate="always",
+ partial_reordering=[("c", "d", "a", "b")],
) as batch_op:
pass
Ensure "d" appears before "c", and "b", appears before "a"::
with op.batch_alter_table(
- "some_table", recreate="always",
- partial_reordering=[("d", "c"), ("b", "a")]
+ "some_table",
+ recreate="always",
+ partial_reordering=[("d", "c"), ("b", "a")],
) as batch_op:
pass
If the :meth:`.Operations.f` is used on a constraint, the naming
convention will not take effect::
- op.add_column('t', 'x', Boolean(name=op.f('ck_bool_t_x')))
+ op.add_column("t", "x", Boolean(name=op.f("ck_bool_t_x")))
Above, the CHECK constraint generated will have the name
``ck_bool_t_x`` regardless of whether or not a naming convention is
``{"ck": "ck_bool_%(table_name)s_%(constraint_name)s"}``, then the
output of the following:
- op.add_column('t', 'x', Boolean(name='x'))
+ op.add_column("t", "x", Boolean(name="x"))
will be::
e.g.::
from alembic import op
+
op.create_primary_key(
- "pk_my_table", "my_table",
- ["id", "version"]
- )
+ "pk_my_table", "my_table", ["id", "version"]
+ )
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
e.g.::
from alembic import op
+
op.create_foreign_key(
- "fk_user_address", "address",
- "user", ["user_id"], ["id"])
+ "fk_user_address",
+ "address",
+ "user",
+ ["user_id"],
+ ["id"],
+ )
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
with batch_alter_table("address") as batch_op:
batch_op.create_foreign_key(
- "fk_user_address",
- "user", ["user_id"], ["id"])
+ "fk_user_address",
+ "user",
+ ["user_id"],
+ ["id"],
+ )
.. seealso::
op.create_check_constraint(
"ck_user_name_len",
"user",
- func.len(column('name')) > 5
+ func.len(column("name")) > 5,
)
CHECK constraints are usually against a SQL expression, so ad-hoc
e.g.::
from alembic import op
- op.create_index('ik_test', 't1', ['foo', 'bar'])
+
+ op.create_index("ik_test", "t1", ["foo", "bar"])
Functional indexes can be produced by using the
:func:`sqlalchemy.sql.expression.text` construct::
from alembic import op
from sqlalchemy import text
- op.create_index('ik_test', 't1', [text('lower(foo)')])
+
+ op.create_index("ik_test", "t1", [text("lower(foo)")])
:param index_name: name of the index.
:param table_name: name of the owning table.
from alembic import op
op.create_table(
- 'account',
- Column('id', INTEGER, primary_key=True),
- Column('name', VARCHAR(50), nullable=False),
- Column('description', NVARCHAR(200)),
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ "account",
+ Column("id", INTEGER, primary_key=True),
+ Column("name", VARCHAR(50), nullable=False),
+ Column("description", NVARCHAR(200)),
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
Note that :meth:`.create_table` accepts
from alembic import op
account_table = op.create_table(
- 'account',
- Column('id', INTEGER, primary_key=True),
- Column('name', VARCHAR(50), nullable=False),
- Column('description', NVARCHAR(200)),
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ "account",
+ Column("id", INTEGER, primary_key=True),
+ Column("name", VARCHAR(50), nullable=False),
+ Column("description", NVARCHAR(200)),
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
op.bulk_insert(
[
{"name": "A1", "description": "account 1"},
{"name": "A2", "description": "account 2"},
- ]
+ ],
)
:param table_name: Name of the table
from alembic import op
from sqlalchemy import Column, String
- op.add_column('organization',
- Column('name', String())
- )
+ op.add_column("organization", Column("name", String()))
The provided :class:`~sqlalchemy.schema.Column` object can also
specify a :class:`~sqlalchemy.schema.ForeignKey`, referencing
from alembic import op
from sqlalchemy import Column, INTEGER, ForeignKey
- op.add_column('organization',
- Column('account_id', INTEGER, ForeignKey('accounts.id'))
+ op.add_column(
+ "organization",
+ Column("account_id", INTEGER, ForeignKey("accounts.id")),
)
Note that this statement uses the :class:`~sqlalchemy.schema.Column`
from sqlalchemy import Column, TIMESTAMP, func
# specify "DEFAULT NOW" along with the column add
- op.add_column('account',
- Column('timestamp', TIMESTAMP, server_default=func.now())
+ op.add_column(
+ "account",
+ Column("timestamp", TIMESTAMP, server_default=func.now()),
)
:param table_name: String name of the parent table.
e.g.::
- drop_column('organization', 'account_id')
+ drop_column("organization", "account_id")
:param table_name: name of table
:param column_name: name of column
from sqlalchemy import String, Integer, Date
# Create an ad-hoc table to use for the insert statement.
- accounts_table = table('account',
- column('id', Integer),
- column('name', String),
- column('create_date', Date)
+ accounts_table = table(
+ "account",
+ column("id", Integer),
+ column("name", String),
+ column("create_date", Date),
)
- op.bulk_insert(accounts_table,
+ op.bulk_insert(
+ accounts_table,
[
- {'id':1, 'name':'John Smith',
- 'create_date':date(2010, 10, 5)},
- {'id':2, 'name':'Ed Williams',
- 'create_date':date(2007, 5, 27)},
- {'id':3, 'name':'Wendy Jones',
- 'create_date':date(2008, 8, 15)},
- ]
+ {
+ "id": 1,
+ "name": "John Smith",
+ "create_date": date(2010, 10, 5),
+ },
+ {
+ "id": 2,
+ "name": "Ed Williams",
+ "create_date": date(2007, 5, 27),
+ },
+ {
+ "id": 3,
+ "name": "Wendy Jones",
+ "create_date": date(2008, 8, 15),
+ },
+ ],
)
When using --sql mode, some datatypes may not render inline
automatically, such as dates and other special types. When this
issue is present, :meth:`.Operations.inline_literal` may be used::
- op.bulk_insert(accounts_table,
+ op.bulk_insert(
+ accounts_table,
[
- {'id':1, 'name':'John Smith',
- 'create_date':op.inline_literal("2010-10-05")},
- {'id':2, 'name':'Ed Williams',
- 'create_date':op.inline_literal("2007-05-27")},
- {'id':3, 'name':'Wendy Jones',
- 'create_date':op.inline_literal("2008-08-15")},
+ {
+ "id": 1,
+ "name": "John Smith",
+ "create_date": op.inline_literal("2010-10-05"),
+ },
+ {
+ "id": 2,
+ "name": "Ed Williams",
+ "create_date": op.inline_literal("2007-05-27"),
+ },
+ {
+ "id": 3,
+ "name": "Wendy Jones",
+ "create_date": op.inline_literal("2008-08-15"),
+ },
],
- multiinsert=False
+ multiinsert=False,
)
When using :meth:`.Operations.inline_literal` in conjunction with
config.set_main_option("script_location", "myapp:migrations")
script = ScriptDirectory.from_config(config)
+
def my_function(rev, context):
'''do something with revision "rev", which
will be the current database revision,
and "context", which is the MigrationContext
that the env.py will create'''
+
with EnvironmentContext(
config,
script,
- fn = my_function,
- as_sql = False,
- starting_rev = 'base',
- destination_rev = 'head',
- tag = "sometag"
+ fn=my_function,
+ as_sql=False,
+ starting_rev="base",
+ destination_rev="head",
+ tag="sometag",
):
script.run_env()
# from within env.py script
from alembic import context
+
migration_context = context.get_context()
For usage outside of an ``env.py`` script, such as for
# in any application, outside of the normal Alembic environment
from alembic.operations import Operations
+
op = Operations(context)
op.alter_column("mytable", "somecolumn", nullable=True)