diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-03-03 10:12:09 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-03-03 10:12:45 -0500 |
commit | 94ac796772b25ae3aafb83a846158fe8c3729c90 (patch) | |
tree | d6706c17da388a8a73f0279f49e44c91f58e4548 /docs | |
parent | dfb82e2cc13f6c508543a3ac47d18ec7ae54887a (diff) | |
download | alembic-94ac796772b25ae3aafb83a846158fe8c3729c90.tar.gz |
Add custom table column sorting example
Change-Id: Ie953ba34ed8e6cbf90e3070494279174ebca5d1a
Diffstat (limited to 'docs')
-rw-r--r-- | docs/build/api/autogenerate.rst | 10 | ||||
-rw-r--r-- | docs/build/cookbook.rst | 96 |
2 files changed, 106 insertions, 0 deletions
diff --git a/docs/build/api/autogenerate.rst b/docs/build/api/autogenerate.rst index c4678e1..230d42d 100644 --- a/docs/build/api/autogenerate.rst +++ b/docs/build/api/autogenerate.rst @@ -203,6 +203,16 @@ structure consisting of zero or more :class:`.MigrationScript` directives. The :func:`.command.revision` command will then produce scripts corresponding to whatever is in this list. +.. seealso:: + + More examples of using :paramref:`.EnvironmentContext.configure.process_revision_directives` + + :ref:`cookbook_no_empty_migrations` + + :ref:`cookbook_dont_emit_drop_index` + + :ref:`cookbook_custom_sorting_create_table` + .. autofunction:: alembic.autogenerate.render_python_code .. _autogen_rewriter: diff --git a/docs/build/cookbook.rst b/docs/build/cookbook.rst index 0d034af..83cabdb 100644 --- a/docs/build/cookbook.rst +++ b/docs/build/cookbook.rst @@ -774,6 +774,8 @@ recreated again within the downgrade for this migration:: INFO [sqlalchemy.engine.base.Engine] {} INFO [sqlalchemy.engine.base.Engine] COMMIT +.. _cookbook_no_empty_migrations: + Don't Generate Empty Migrations with Autogenerate ================================================= @@ -809,6 +811,8 @@ any operations:: with context.begin_transaction(): context.run_migrations() +.. _cookbook_dont_emit_drop_index: + Don't emit DROP INDEX when the table is to be dropped as well ============================================================= @@ -934,6 +938,98 @@ the local :class:`.MetaData` collection:: include_object = include_object ) +.. _cookbook_custom_sorting_create_table: + +Apply Custom Sorting to Table Columns within CREATE TABLE +========================================================== + +This example illustrates use of the :class:`.Rewriter` object introduced +at :ref:`autogen_rewriter`. While the rewriter grants access to the +individual :class:`.ops.MigrateOperation` objects, there are sometimes some +special techniques required to get around some structural limitations that +are present. + +One is when trying to reorganize the order of columns in a +table within a :class:`.ops.CreateTableOp` directive. This directive, when +generated by autogenerate, actually holds onto the original :class:`.Table` +object as the source of its information, so attempting to reorder the +:attr:`.ops.CreateTableOp.columns` collection will usually have no effect. +Instead, a new :class:`.ops.CreateTableOp` object may be constructed with the +new ordering. However, a second issue is that the :class:`.Column` objects +inside will already be associated with the :class:`.Table` that is from the +model being autogenerated, meaning they can't be reassigned directly to a new +:class:`.Table`. To get around this, we can copy all the columns and constraints +using methods like :meth:`.Column.copy`. + +Below we use :class:`.Rewriter` to create a new :class:`.ops.CreateTableOp` +directive and to copy the :class:`.Column` objects from one into another, +copying each column or constraint object and applying a new sorting scheme:: + + # in env.py + + from alembic.operations import ops + from alembic.autogenerate import rewriter + + writer = rewriter.Rewriter() + + @writer.rewrites(ops.CreateTableOp) + def order_columns(context, revision, op): + + special_names = {"id": -100, "created_at": 1001, "updated_at": 1002} + + cols_by_key = [ + ( + special_names.get(col.key, index) + if isinstance(col, Column) + else 2000, + col.copy(), + ) + for index, col in enumerate(op.columns) + ] + + columns = [ + col for idx, col in sorted(cols_by_key, key=lambda entry: entry[0]) + ] + return ops.CreateTableOp( + op.table_name, columns, schema=op.schema, **op.kw) + + + # ... + + context.configure( + # ... + process_revision_directives=writer + ) + + +Above, when we apply the ``writer`` to a table such as:: + + Table( + "my_table", + m, + Column("data", String(50)), + Column("created_at", DateTime), + Column("id", Integer, primary_key=True), + Column("updated_at", DateTime), + UniqueConstraint("data", name="uq_data") + ) + + +This will render in the autogenerated file as:: + + def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "my_table", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("data", sa.String(length=50), nullable=True), + sa.Column("created_at", sa.DateTime(), nullable=True), + sa.Column("updated_at", sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("data", name="uq_data"), + ) + # ### end Alembic commands ### + Don't emit CREATE TABLE statements for Views ============================================ |