How to use insert_before/insert_after using a rewriter. #1170
-
``I inherited some migration code and we semi routinely need to add columns to existing tables. The instructions for the migration says to add the insert_before or insert_after once alembic has been ran but I was hoping to fold this in since I know the order of the columns based on a list which will be easy to programmatically add. The downside is I do not understand how this rewriter works nor what its asking me for. I tried using an example from the code and have tried many different ways. Here is an example seemed close/simple:
My result:
If there is any more info needed let me know. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 6 replies
-
I think you just want to take the AddColumnOp you were given and set op.insert_before # ... fragmented env.py script ....
from alembic.autogenerate import rewriter
from alembic.operations import ops
writer = rewriter.Rewriter()
@writer.rewrites(ops.AddColumnOp)
def add_column(context, revision, op):
op.insert_before = "column_one"
return op note insert_before refers to the name of a column, not a table |
Beta Was this translation helpful? Give feedback.
-
I came up with my own solution for this. We have substantial amount of tables/columns and we adopted alembic to reduce human error so the more we can do programmatically the better. Here is the solution I did, I will also do a pull request sometime for this once I've run it enough. But here is the code you would put in your env.py. def _add_column_custom(autogen_context, op):
kwargs = None
if op.kw:
kwargs = [(key, str(value)) for key, value in op.kw.items()]
schema, tname, column = op.schema, op.table_name, op.column
if autogen_context._has_batch:
template = "%(prefix)sadd_column(%(column)s)"
else:
template = "%(prefix)sadd_column(%(tname)r, %(column)s"
if schema:
template += ", schema=%(schema)r"
template += ")"
print(kwargs)
text = template % {
"prefix": _alembic_autogenerate_prefix(autogen_context),
"tname": tname,
"column": _render_column(column, autogen_context, kwargs),
"schema": schema,
}
return text
def _render_column_custom(column, autogen_context, kwargs=None):
rendered = _user_defined_render("column", column, autogen_context)
if rendered is not False:
return rendered
args = []
opts = []
if column.server_default:
rendered = _render_server_default( # type:ignore[assignment]
column.server_default, autogen_context
)
if rendered:
if _should_render_server_default_positionally(
column.server_default
):
args.append(rendered)
else:
opts.append(("server_default", rendered))
if (
column.autoincrement is not None
and column.autoincrement != sqla_compat.AUTOINCREMENT_DEFAULT
):
opts.append(("autoincrement", column.autoincrement))
if column.nullable is not None:
opts.append(("nullable", column.nullable))
if column.system:
opts.append(("system", column.system))
comment = column.comment
if comment:
opts.append(("comment", "%r" % comment))
if kwargs:
opts += kwargs
return "%(prefix)sColumn(%(name)r, %(type)s, %(args)s%(kwargs)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"name": _ident(column.name),
"type": _repr_type(column.type, autogen_context),
"args": ", ".join([str(arg) for arg in args]) + ", " if args else "",
"kwargs": (
", ".join(
["%s=%s" % (kwname, val) for kwname, val in opts]
+ [
"%s=%s"
% (key, _render_potential_expr(val, autogen_context))
for key, val in sqla_compat._column_kwargs(column).items()
]
)
),
}
_render_column = _render_column_custom
_add_column = _add_column_custom |
Beta Was this translation helpful? Give feedback.
I came up with my own solution for this. We have substantial amount of tables/columns and we adopted alembic to reduce human error so the more we can do programmatically the better. Here is the solution I did, I will also do a pull request sometime for this once I've run it enough.
But here is the code you would put in your env.py.