관리-도구
편집 파일: autogenerate.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Autogeneration — Alembic 0.8.3 documentation</title> <link rel="stylesheet" href="../_static/nature_override.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/changelog.css" type="text/css" /> <link rel="stylesheet" href="../_static/sphinx_paramlinks.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../', VERSION: '0.8.3', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../_static/jquery.js"></script> <script type="text/javascript" src="../_static/underscore.js"></script> <script type="text/javascript" src="../_static/doctools.js"></script> <link rel="top" title="Alembic 0.8.3 documentation" href="../index.html" /> <link rel="up" title="API Details" href="index.html" /> <link rel="next" title="Script Directory" href="script.html" /> <link rel="prev" title="Operation Directives" href="operations.html" /> </head> <body role="document"> <div class="related" role="navigation" aria-label="related navigation"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../genindex.html" title="General Index" accesskey="I">index</a></li> <li class="right" > <a href="../py-modindex.html" title="Python Module Index" >modules</a> |</li> <li class="right" > <a href="script.html" title="Script Directory" accesskey="N">next</a> |</li> <li class="right" > <a href="operations.html" title="Operation Directives" accesskey="P">previous</a> |</li> <li class="nav-item nav-item-0"><a href="../index.html">Alembic 0.8.3 documentation</a> »</li> <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">API Details</a> »</li> </ul> </div> <div class="document"> <div class="documentwrapper"> <div class="bodywrapper"> <div class="body" role="main"> <div class="section" id="autogeneration"> <span id="alembic-autogenerate-toplevel"></span><h1>Autogeneration<a class="headerlink" href="#autogeneration" title="Permalink to this headline">¶</a></h1> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">this section discusses the <strong>internal API of Alembic</strong> as regards the autogeneration feature of the <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span></code> command. This section is only useful for developers who wish to extend the capabilities of Alembic. For general documentation on the autogenerate feature, please see <a class="reference internal" href="../autogenerate.html"><em>Auto Generating Migrations</em></a>.</p> </div> <p>The autogeneration system has a wide degree of public API, including the following areas:</p> <ol class="arabic simple"> <li>The ability to do a “diff” of a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> object against a database, and receive a data structure back. This structure is available either as a rudimentary list of changes, or as a <a class="reference internal" href="../ops.html#alembic.operations.MigrateOperation" title="alembic.operations.MigrateOperation"><code class="xref py py-class docutils literal"><span class="pre">MigrateOperation</span></code></a> structure.</li> <li>The ability to alter how the <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span></code> command generates revision scripts, including support for multiple revision scripts generated in one pass.</li> <li>The ability to add new operation directives to autogeneration, including custom schema/model comparison functions and revision script rendering.</li> </ol> <div class="section" id="getting-diffs"> <h2>Getting Diffs<a class="headerlink" href="#getting-diffs" title="Permalink to this headline">¶</a></h2> <p>The simplest API autogenerate provides is the “schema comparison” API; these are simple functions that will run all registered “comparison” functions between a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> object and a database backend to produce a structure showing how they differ. The two functions provided are <a class="reference internal" href="#alembic.autogenerate.compare_metadata" title="alembic.autogenerate.compare_metadata"><code class="xref py py-func docutils literal"><span class="pre">compare_metadata()</span></code></a>, which is more of the “legacy” function that produces diff tuples, and <a class="reference internal" href="#alembic.autogenerate.produce_migrations" title="alembic.autogenerate.produce_migrations"><code class="xref py py-func docutils literal"><span class="pre">produce_migrations()</span></code></a>, which produces a structure consisting of operation directives detailed in <a class="reference internal" href="operations.html#alembic-operations-toplevel"><span>Operation Directives</span></a>.</p> <dl class="function"> <dt id="alembic.autogenerate.compare_metadata"> <code class="descclassname">alembic.autogenerate.</code><code class="descname">compare_metadata</code><span class="sig-paren">(</span><em>context</em>, <em>metadata</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.compare_metadata" title="Permalink to this definition">¶</a></dt> <dd><p>Compare a database schema to that given in a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> instance.</p> <p>The database connection is presented in the context of a <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext" title="alembic.runtime.migration.MigrationContext"><code class="xref py py-class docutils literal"><span class="pre">MigrationContext</span></code></a> object, which provides database connectivity as well as optional comparison functions to use for datatypes and server defaults - see the “autogenerate” arguments at <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-meth docutils literal"><span class="pre">EnvironmentContext.configure()</span></code></a> for details on these.</p> <p>The return format is a list of “diff” directives, each representing individual differences:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.migration</span> <span class="kn">import</span> <span class="n">MigrationContext</span> <span class="kn">from</span> <span class="nn">alembic.autogenerate</span> <span class="kn">import</span> <span class="n">compare_metadata</span> <span class="kn">from</span> <span class="nn">sqlalchemy.schema</span> <span class="kn">import</span> <span class="n">SchemaItem</span> <span class="kn">from</span> <span class="nn">sqlalchemy.types</span> <span class="kn">import</span> <span class="n">TypeEngine</span> <span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="p">(</span><span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span><span class="p">,</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">Table</span><span class="p">)</span> <span class="kn">import</span> <span class="nn">pprint</span> <span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s">"sqlite://"</span><span class="p">)</span> <span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'''</span> <span class="s"> create table foo (</span> <span class="s"> id integer not null primary key,</span> <span class="s"> old_data varchar,</span> <span class="s"> x integer</span> <span class="s"> )'''</span><span class="p">)</span> <span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'''</span> <span class="s"> create table bar (</span> <span class="s"> data varchar</span> <span class="s"> )'''</span><span class="p">)</span> <span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span> <span class="n">Table</span><span class="p">(</span><span class="s">'foo'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">Column</span><span class="p">(</span><span class="s">'id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">Column</span><span class="p">(</span><span class="s">'data'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">),</span> <span class="n">Column</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="p">)</span> <span class="n">Table</span><span class="p">(</span><span class="s">'bat'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">Column</span><span class="p">(</span><span class="s">'info'</span><span class="p">,</span> <span class="n">String</span><span class="p">)</span> <span class="p">)</span> <span class="n">mc</span> <span class="o">=</span> <span class="n">MigrationContext</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">())</span> <span class="n">diff</span> <span class="o">=</span> <span class="n">compare_metadata</span><span class="p">(</span><span class="n">mc</span><span class="p">,</span> <span class="n">metadata</span><span class="p">)</span> <span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">diff</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span> </pre></div> </div> <p>Output:</p> <div class="highlight-python"><div class="highlight"><pre>[ ( '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)]] </pre></div> </div> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple"> <li><span class="target" id="alembic.autogenerate.compare_metadata.params.context"></span><strong>context</strong><a class="paramlink headerlink reference internal" href="#alembic.autogenerate.compare_metadata.params.context">¶</a> – a <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext" title="alembic.runtime.migration.MigrationContext"><code class="xref py py-class docutils literal"><span class="pre">MigrationContext</span></code></a> instance.</li> <li><span class="target" id="alembic.autogenerate.compare_metadata.params.metadata"></span><strong>metadata</strong><a class="paramlink headerlink reference internal" href="#alembic.autogenerate.compare_metadata.params.metadata">¶</a> – a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> instance.</li> </ul> </td> </tr> </tbody> </table> <div class="admonition seealso"> <p class="first admonition-title">See also</p> <p class="last"><a class="reference internal" href="#alembic.autogenerate.produce_migrations" title="alembic.autogenerate.produce_migrations"><code class="xref py py-func docutils literal"><span class="pre">produce_migrations()</span></code></a> - produces a <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> structure based on metadata comparison.</p> </div> </dd></dl> <dl class="function"> <dt id="alembic.autogenerate.produce_migrations"> <code class="descclassname">alembic.autogenerate.</code><code class="descname">produce_migrations</code><span class="sig-paren">(</span><em>context</em>, <em>metadata</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.produce_migrations" title="Permalink to this definition">¶</a></dt> <dd><p>Produce a <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> structure based on schema comparison.</p> <p>This function does essentially what <a class="reference internal" href="#alembic.autogenerate.compare_metadata" title="alembic.autogenerate.compare_metadata"><code class="xref py py-func docutils literal"><span class="pre">compare_metadata()</span></code></a> does, but then runs the resulting list of diffs to produce the full <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> object. For an example of what this looks like, see the example in <a class="reference internal" href="#customizing-revision"><span>Customizing Revision Generation</span></a>.</p> <div class="versionadded"> <p><span class="versionmodified">New in version 0.8.0.</span></p> </div> <div class="admonition seealso"> <p class="first admonition-title">See also</p> <p class="last"><a class="reference internal" href="#alembic.autogenerate.compare_metadata" title="alembic.autogenerate.compare_metadata"><code class="xref py py-func docutils literal"><span class="pre">compare_metadata()</span></code></a> - returns more fundamental “diff” data from comparing a schema.</p> </div> </dd></dl> </div> <div class="section" id="customizing-revision-generation"> <span id="customizing-revision"></span><h2>Customizing Revision Generation<a class="headerlink" href="#customizing-revision-generation" title="Permalink to this headline">¶</a></h2> <div class="versionadded"> <p><span class="versionmodified">New in version 0.8.0: </span>- the <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span></code> system is now customizable.</p> </div> <p>The <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span></code> command, also available programmatically via <a class="reference internal" href="commands.html#alembic.command.revision" title="alembic.command.revision"><code class="xref py py-func docutils literal"><span class="pre">command.revision()</span></code></a>, essentially produces a single migration script after being run. Whether or not the <code class="docutils literal"><span class="pre">--autogenerate</span></code> option was specified basically determines if this script is a blank revision script with empty <code class="docutils literal"><span class="pre">upgrade()</span></code> and <code class="docutils literal"><span class="pre">downgrade()</span></code> functions, or was produced with alembic operation directives as the result of autogenerate.</p> <p>In either case, the system creates a full plan of what is to be done in the form of a <a class="reference internal" href="../ops.html#alembic.operations.MigrateOperation" title="alembic.operations.MigrateOperation"><code class="xref py py-class docutils literal"><span class="pre">MigrateOperation</span></code></a> structure, which is then used to produce the script.</p> <p>For example, suppose we ran <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span> <span class="pre">--autogenerate</span></code>, and the end result was that it produced a new revision <code class="docutils literal"><span class="pre">'eced083f5df'</span></code> with the following contents:</p> <div class="highlight-python"><div class="highlight"><pre><span class="sd">"""create the organization table."""</span> <span class="c"># revision identifiers, used by Alembic.</span> <span class="n">revision</span> <span class="o">=</span> <span class="s">'eced083f5df'</span> <span class="n">down_revision</span> <span class="o">=</span> <span class="s">'beafc7d709f'</span> <span class="kn">from</span> <span class="nn">alembic</span> <span class="kn">import</span> <span class="n">op</span> <span class="kn">import</span> <span class="nn">sqlalchemy</span> <span class="kn">as</span> <span class="nn">sa</span> <span class="k">def</span> <span class="nf">upgrade</span><span class="p">():</span> <span class="n">op</span><span class="o">.</span><span class="n">create_table</span><span class="p">(</span> <span class="s">'organization'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'id'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Integer</span><span class="p">(),</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'name'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="p">)</span> <span class="n">op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span> <span class="s">'user'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'organization_id'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Integer</span><span class="p">())</span> <span class="p">)</span> <span class="n">op</span><span class="o">.</span><span class="n">create_foreign_key</span><span class="p">(</span> <span class="s">'org_fk'</span><span class="p">,</span> <span class="s">'user'</span><span class="p">,</span> <span class="s">'organization'</span><span class="p">,</span> <span class="p">[</span><span class="s">'organization_id'</span><span class="p">],</span> <span class="p">[</span><span class="s">'id'</span><span class="p">]</span> <span class="p">)</span> <span class="k">def</span> <span class="nf">downgrade</span><span class="p">():</span> <span class="n">op</span><span class="o">.</span><span class="n">drop_constraint</span><span class="p">(</span><span class="s">'org_fk'</span><span class="p">,</span> <span class="s">'user'</span><span class="p">)</span> <span class="n">op</span><span class="o">.</span><span class="n">drop_column</span><span class="p">(</span><span class="s">'user'</span><span class="p">,</span> <span class="s">'organization_id'</span><span class="p">)</span> <span class="n">op</span><span class="o">.</span><span class="n">drop_table</span><span class="p">(</span><span class="s">'organization'</span><span class="p">)</span> </pre></div> </div> <p>The above script is generated by a <a class="reference internal" href="../ops.html#alembic.operations.MigrateOperation" title="alembic.operations.MigrateOperation"><code class="xref py py-class docutils literal"><span class="pre">MigrateOperation</span></code></a> structure that looks like this:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.operations</span> <span class="kn">import</span> <span class="n">ops</span> <span class="kn">import</span> <span class="nn">sqlalchemy</span> <span class="kn">as</span> <span class="nn">sa</span> <span class="n">migration_script</span> <span class="o">=</span> <span class="n">ops</span><span class="o">.</span><span class="n">MigrationScript</span><span class="p">(</span> <span class="s">'eced083f5df'</span><span class="p">,</span> <span class="n">ops</span><span class="o">.</span><span class="n">UpgradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">CreateTableOp</span><span class="p">(</span> <span class="s">'organization'</span><span class="p">,</span> <span class="p">[</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'id'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Integer</span><span class="p">(),</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'name'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="p">]</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">ModifyTableOps</span><span class="p">(</span> <span class="s">'user'</span><span class="p">,</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">AddColumnOp</span><span class="p">(</span> <span class="s">'user'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="s">'organization_id'</span><span class="p">,</span> <span class="n">sa</span><span class="o">.</span><span class="n">Integer</span><span class="p">())</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">CreateForeignKeyOp</span><span class="p">(</span> <span class="s">'org_fk'</span><span class="p">,</span> <span class="s">'user'</span><span class="p">,</span> <span class="s">'organization'</span><span class="p">,</span> <span class="p">[</span><span class="s">'organization_id'</span><span class="p">],</span> <span class="p">[</span><span class="s">'id'</span><span class="p">]</span> <span class="p">)</span> <span class="p">]</span> <span class="p">)</span> <span class="p">]</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">DowngradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">ModifyTableOps</span><span class="p">(</span> <span class="s">'user'</span><span class="p">,</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">DropConstraintOp</span><span class="p">(</span><span class="s">'org_fk'</span><span class="p">,</span> <span class="s">'user'</span><span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">DropColumnOp</span><span class="p">(</span><span class="s">'user'</span><span class="p">,</span> <span class="s">'organization_id'</span><span class="p">)</span> <span class="p">]</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">DropTableOp</span><span class="p">(</span><span class="s">'organization'</span><span class="p">)</span> <span class="p">]</span> <span class="p">),</span> <span class="n">message</span><span class="o">=</span><span class="s">'create the organization table.'</span> <span class="p">)</span> </pre></div> </div> <p>When we deal with a <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> structure, we can render the upgrade/downgrade sections into strings for debugging purposes using the <a class="reference internal" href="#alembic.autogenerate.render_python_code" title="alembic.autogenerate.render_python_code"><code class="xref py py-func docutils literal"><span class="pre">render_python_code()</span></code></a> helper function:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.autogenerate</span> <span class="kn">import</span> <span class="n">render_python_code</span> <span class="k">print</span><span class="p">(</span><span class="n">render_python_code</span><span class="p">(</span><span class="n">migration_script</span><span class="o">.</span><span class="n">upgrade_ops</span><span class="p">))</span> </pre></div> </div> <p>Renders:</p> <div class="highlight-python"><div class="highlight"><pre>### commands auto generated by Alembic - please adjust! ### op.create_table('organization', sa.Column('id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=50), nullable=False), sa.PrimaryKeyConstraint('id') ) op.add_column('user', sa.Column('organization_id', sa.Integer(), nullable=True)) op.create_foreign_key('org_fk', 'user', 'organization', ['organization_id'], ['id']) ### end Alembic commands ### </pre></div> </div> <p>Given that structures like the above are used to generate new revision files, and that we’d like to be able to alter these as they are created, we then need a system to access this structure when the <a class="reference internal" href="commands.html#alembic.command.revision" title="alembic.command.revision"><code class="xref py py-func docutils literal"><span class="pre">command.revision()</span></code></a> command is used. The <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.process_revision_directives" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.process_revision_directives</span></code></a> parameter gives us a way to alter this. This is a function that is passed the above structure as generated by Alembic, giving us a chance to alter it. For example, if we wanted to put all the “upgrade” operations into a certain branch, and we wanted our script to not have any “downgrade” operations at all, we could build an extension as follows, illustrated within an <code class="docutils literal"><span class="pre">env.py</span></code> script:</p> <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">process_revision_directives</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">revision</span><span class="p">,</span> <span class="n">directives</span><span class="p">):</span> <span class="n">script</span> <span class="o">=</span> <span class="n">directives</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c"># set specific branch</span> <span class="n">script</span><span class="o">.</span><span class="n">head</span> <span class="o">=</span> <span class="s">"mybranch@head"</span> <span class="c"># erase downgrade operations</span> <span class="n">script</span><span class="o">.</span><span class="n">downgrade_ops</span><span class="o">.</span><span class="n">ops</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># ...</span> <span class="k">def</span> <span class="nf">run_migrations_online</span><span class="p">():</span> <span class="c"># ...</span> <span class="k">with</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> <span class="k">as</span> <span class="n">connection</span><span class="p">:</span> <span class="n">context</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span> <span class="n">connection</span><span class="o">=</span><span class="n">connection</span><span class="p">,</span> <span class="n">target_metadata</span><span class="o">=</span><span class="n">target_metadata</span><span class="p">,</span> <span class="n">process_revision_directives</span><span class="o">=</span><span class="n">process_revision_directives</span><span class="p">)</span> <span class="k">with</span> <span class="n">context</span><span class="o">.</span><span class="n">begin_transaction</span><span class="p">():</span> <span class="n">context</span><span class="o">.</span><span class="n">run_migrations</span><span class="p">()</span> </pre></div> </div> <p>Above, the <code class="docutils literal"><span class="pre">directives</span></code> argument is a Python list. We may alter the given structure within this list in-place, or replace it with a new structure consisting of zero or more <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> directives. The <a class="reference internal" href="commands.html#alembic.command.revision" title="alembic.command.revision"><code class="xref py py-func docutils literal"><span class="pre">command.revision()</span></code></a> command will then produce scripts corresponding to whatever is in this list.</p> <dl class="function"> <dt id="alembic.autogenerate.render_python_code"> <code class="descclassname">alembic.autogenerate.</code><code class="descname">render_python_code</code><span class="sig-paren">(</span><em>up_or_down_op</em>, <em>sqlalchemy_module_prefix='sa.'</em>, <em>alembic_module_prefix='op.'</em>, <em>render_as_batch=False</em>, <em>imports=()</em>, <em>render_item=None</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.render_python_code" title="Permalink to this definition">¶</a></dt> <dd><p>Render Python code given an <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> or <a class="reference internal" href="operations.html#alembic.operations.ops.DowngradeOps" title="alembic.operations.ops.DowngradeOps"><code class="xref py py-class docutils literal"><span class="pre">DowngradeOps</span></code></a> object.</p> <p>This is a convenience function that can be used to test the autogenerate output of a user-defined <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> structure.</p> </dd></dl> <div class="section" id="fine-grained-autogenerate-generation-with-rewriters"> <span id="autogen-rewriter"></span><h3>Fine-Grained Autogenerate Generation with Rewriters<a class="headerlink" href="#fine-grained-autogenerate-generation-with-rewriters" title="Permalink to this headline">¶</a></h3> <p>The preceding example illustrated how we can make a simple change to the structure of the operation directives to produce new autogenerate output. For the case where we want to affect very specific parts of the autogenerate stream, we can make a function for <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.process_revision_directives" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.process_revision_directives</span></code></a> which traverses through the whole <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">MigrationScript</span></code></a> structure, locates the elements we care about and modifies them in-place as needed. However, to reduce the boilerplate associated with this task, we can use the <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> object to make this easier. <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> gives us an object that we can pass directly to <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.process_revision_directives" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.process_revision_directives</span></code></a> which we can also attach handler functions onto, keyed to specific types of constructs.</p> <p>Below is an example where we rewrite <a class="reference internal" href="operations.html#alembic.operations.ops.AddColumnOp" title="alembic.operations.ops.AddColumnOp"><code class="xref py py-class docutils literal"><span class="pre">ops.AddColumnOp</span></code></a> directives; based on whether or not the new column is “nullable”, we either return the existing directive, or we return the existing directive with the nullable flag changed, inside of a list with a second directive to alter the nullable flag in a second step:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># ... fragmented env.py script ....</span> <span class="kn">from</span> <span class="nn">alembic.autogenerate</span> <span class="kn">import</span> <span class="n">rewriter</span> <span class="kn">from</span> <span class="nn">alembic.operations</span> <span class="kn">import</span> <span class="n">ops</span> <span class="n">writer</span> <span class="o">=</span> <span class="n">rewriter</span><span class="o">.</span><span class="n">Rewriter</span><span class="p">()</span> <span class="nd">@writer.rewrites</span><span class="p">(</span><span class="n">ops</span><span class="o">.</span><span class="n">AddColumnOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">add_column</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">revision</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="k">if</span> <span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">nullable</span><span class="p">:</span> <span class="k">return</span> <span class="n">op</span> <span class="k">else</span><span class="p">:</span> <span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">nullable</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">return</span> <span class="p">[</span> <span class="n">op</span><span class="p">,</span> <span class="n">ops</span><span class="o">.</span><span class="n">AlterColumnOp</span><span class="p">(</span> <span class="n">op</span><span class="o">.</span><span class="n">table_name</span><span class="p">,</span> <span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">modify_nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">existing_type</span><span class="o">=</span><span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="p">)</span> <span class="p">]</span> <span class="c"># ... later ...</span> <span class="k">def</span> <span class="nf">run_migrations_online</span><span class="p">():</span> <span class="c"># ...</span> <span class="k">with</span> <span class="n">connectable</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> <span class="k">as</span> <span class="n">connection</span><span class="p">:</span> <span class="n">context</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span> <span class="n">connection</span><span class="o">=</span><span class="n">connection</span><span class="p">,</span> <span class="n">target_metadata</span><span class="o">=</span><span class="n">target_metadata</span><span class="p">,</span> <span class="n">process_revision_directives</span><span class="o">=</span><span class="n">writer</span> <span class="p">)</span> <span class="k">with</span> <span class="n">context</span><span class="o">.</span><span class="n">begin_transaction</span><span class="p">():</span> <span class="n">context</span><span class="o">.</span><span class="n">run_migrations</span><span class="p">()</span> </pre></div> </div> <p>Above, in a full <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript" title="alembic.operations.ops.MigrationScript"><code class="xref py py-class docutils literal"><span class="pre">ops.MigrationScript</span></code></a> structure, the <a class="reference internal" href="ddl.html#alembic.ddl.base.AddColumn" title="alembic.ddl.base.AddColumn"><code class="xref py py-class docutils literal"><span class="pre">AddColumn</span></code></a> directives would be present within the paths <code class="docutils literal"><span class="pre">MigrationScript->UpgradeOps->ModifyTableOps</span></code> and <code class="docutils literal"><span class="pre">MigrationScript->DowngradeOps->ModifyTableOps</span></code>. The <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> handles traversing into these structures as well as rewriting them as needed so that we only need to code for the specific object we care about.</p> <dl class="class"> <dt id="alembic.autogenerate.rewriter.Rewriter"> <em class="property">class </em><code class="descclassname">alembic.autogenerate.rewriter.</code><code class="descname">Rewriter</code><a class="headerlink" href="#alembic.autogenerate.rewriter.Rewriter" title="Permalink to this definition">¶</a></dt> <dd><p>A helper object that allows easy ‘rewriting’ of ops streams.</p> <p>The <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> object is intended to be passed along to the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.process_revision_directives" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.process_revision_directives</span></code></a> parameter in an <code class="docutils literal"><span class="pre">env.py</span></code> script. Once constructed, any number of “rewrites” functions can be associated with it, which will be given the opportunity to modify the structure without having to have explicit knowledge of the overall structure.</p> <p>The function is passed the <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext" title="alembic.runtime.migration.MigrationContext"><code class="xref py py-class docutils literal"><span class="pre">MigrationContext</span></code></a> object and <code class="docutils literal"><span class="pre">revision</span></code> tuple that are passed to the <code class="xref py py-paramref docutils literal"><span class="pre">Environment</span> <span class="pre">Context.configure.process_revision_directives</span></code> function normally, and the third argument is an individual directive of the type noted in the decorator. The function has the choice of returning a single op directive, which normally can be the directive that was actually passed, or a new directive to replace it, or a list of zero or more directives to replace it.</p> <div class="admonition seealso"> <p class="first admonition-title">See also</p> <p class="last"><a class="reference internal" href="#autogen-rewriter"><span>Fine-Grained Autogenerate Generation with Rewriters</span></a> - usage example</p> </div> <div class="versionadded"> <p><span class="versionmodified">New in version 0.8.</span></p> </div> <dl class="method"> <dt id="alembic.autogenerate.rewriter.Rewriter.chain"> <code class="descname">chain</code><span class="sig-paren">(</span><em>other</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.rewriter.Rewriter.chain" title="Permalink to this definition">¶</a></dt> <dd><p>Produce a “chain” of this <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> to another.</p> <p>This allows two rewriters to operate serially on a stream, e.g.:</p> <div class="highlight-python"><div class="highlight"><pre><span class="n">writer1</span> <span class="o">=</span> <span class="n">autogenerate</span><span class="o">.</span><span class="n">Rewriter</span><span class="p">()</span> <span class="n">writer2</span> <span class="o">=</span> <span class="n">autogenerate</span><span class="o">.</span><span class="n">Rewriter</span><span class="p">()</span> <span class="nd">@writer1.rewrites</span><span class="p">(</span><span class="n">ops</span><span class="o">.</span><span class="n">AddColumnOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">add_column_nullable</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">revision</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">nullable</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">return</span> <span class="n">op</span> <span class="nd">@writer2.rewrites</span><span class="p">(</span><span class="n">ops</span><span class="o">.</span><span class="n">AddColumnOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">add_column_idx</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">revision</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="n">idx_op</span> <span class="o">=</span> <span class="n">ops</span><span class="o">.</span><span class="n">CreateIndexOp</span><span class="p">(</span> <span class="s">'ixc'</span><span class="p">,</span> <span class="n">op</span><span class="o">.</span><span class="n">table_name</span><span class="p">,</span> <span class="p">[</span><span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">name</span><span class="p">])</span> <span class="k">return</span> <span class="p">[</span> <span class="n">op</span><span class="p">,</span> <span class="n">idx_op</span> <span class="p">]</span> <span class="n">writer</span> <span class="o">=</span> <span class="n">writer1</span><span class="o">.</span><span class="n">chain</span><span class="p">(</span><span class="n">writer2</span><span class="p">)</span> </pre></div> </div> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><span class="target" id="alembic.autogenerate.rewriter.Rewriter.chain.params.other"></span><strong>other</strong><a class="paramlink headerlink reference internal" href="#alembic.autogenerate.rewriter.Rewriter.chain.params.other">¶</a> – a <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> instance</td> </tr> <tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">a new <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> that will run the operations of this writer, then the “other” writer, in succession.</td> </tr> </tbody> </table> </dd></dl> <dl class="method"> <dt id="alembic.autogenerate.rewriter.Rewriter.rewrites"> <code class="descname">rewrites</code><span class="sig-paren">(</span><em>operator</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.rewriter.Rewriter.rewrites" title="Permalink to this definition">¶</a></dt> <dd><p>Register a function as rewriter for a given type.</p> <p>The function should receive three arguments, which are the <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext" title="alembic.runtime.migration.MigrationContext"><code class="xref py py-class docutils literal"><span class="pre">MigrationContext</span></code></a>, a <code class="docutils literal"><span class="pre">revision</span></code> tuple, and an op directive of the type indicated. E.g.:</p> <div class="highlight-python"><div class="highlight"><pre><span class="nd">@writer1.rewrites</span><span class="p">(</span><span class="n">ops</span><span class="o">.</span><span class="n">AddColumnOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">add_column_nullable</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">revision</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="n">op</span><span class="o">.</span><span class="n">column</span><span class="o">.</span><span class="n">nullable</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">return</span> <span class="n">op</span> </pre></div> </div> </dd></dl> </dd></dl> </div> <div class="section" id="revision-generation-with-multiple-engines-run-migrations-calls"> <span id="autogen-customizing-multiengine-revision"></span><h3>Revision Generation with Multiple Engines / <code class="docutils literal"><span class="pre">run_migrations()</span></code> calls<a class="headerlink" href="#revision-generation-with-multiple-engines-run-migrations-calls" title="Permalink to this headline">¶</a></h3> <p>A lesser-used technique which allows autogenerated migrations to run against multiple databse backends at once, generating changes into a single migration script, is illustrated in the provided <code class="docutils literal"><span class="pre">multidb</span></code> template. This template features a special <code class="docutils literal"><span class="pre">env.py</span></code> which iterates through multiple <a class="reference external" href="http://www.sqlalchemy.org/docs/core/connections.html#sqlalchemy.engine.Engine" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Engine</span></code></a> instances and calls upon <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext.run_migrations" title="alembic.runtime.migration.MigrationContext.run_migrations"><code class="xref py py-meth docutils literal"><span class="pre">MigrationContext.run_migrations()</span></code></a> for each:</p> <div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">rec</span> <span class="ow">in</span> <span class="n">engines</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">"Migrating database </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span> <span class="n">context</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span> <span class="n">connection</span><span class="o">=</span><span class="n">rec</span><span class="p">[</span><span class="s">'connection'</span><span class="p">],</span> <span class="n">upgrade_token</span><span class="o">=</span><span class="s">"</span><span class="si">%s</span><span class="s">_upgrades"</span> <span class="o">%</span> <span class="n">name</span><span class="p">,</span> <span class="n">downgrade_token</span><span class="o">=</span><span class="s">"</span><span class="si">%s</span><span class="s">_downgrades"</span> <span class="o">%</span> <span class="n">name</span><span class="p">,</span> <span class="n">target_metadata</span><span class="o">=</span><span class="n">target_metadata</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">)</span> <span class="n">context</span><span class="o">.</span><span class="n">run_migrations</span><span class="p">(</span><span class="n">engine_name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span> </pre></div> </div> <p>Above, <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext.run_migrations" title="alembic.runtime.migration.MigrationContext.run_migrations"><code class="xref py py-meth docutils literal"><span class="pre">MigrationContext.run_migrations()</span></code></a> is run multiple times, once for each engine. Within the context of autogeneration, each time the method is called the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.upgrade_token" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">upgrade_token</span></code></a> and <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.downgrade_token" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">downgrade_token</span></code></a> parameters are changed, so that the collection of template variables gains distinct entries for each engine, which are then referred to explicitly within <code class="docutils literal"><span class="pre">script.py.mako</span></code>.</p> <p>In terms of the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.process_revision_directives" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.process_revision_directives</span></code></a> hook, the behavior here is that the <code class="docutils literal"><span class="pre">process_revision_directives</span></code> hook is invoked <strong>multiple times, once for each call to context.run_migrations()</strong>. This means that if a multi-<code class="docutils literal"><span class="pre">run_migrations()</span></code> approach is to be combined with the <code class="docutils literal"><span class="pre">process_revision_directives</span></code> hook, care must be taken to use the hook appropriately.</p> <p>The first point to note is that when a <strong>second</strong> call to <code class="docutils literal"><span class="pre">run_migrations()</span></code> occurs, the <code class="docutils literal"><span class="pre">.upgrade_ops</span></code> and <code class="docutils literal"><span class="pre">.downgrade_ops</span></code> attributes are <strong>converted into Python lists</strong>, and new <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> and <a class="reference internal" href="operations.html#alembic.operations.ops.DowngradeOps" title="alembic.operations.ops.DowngradeOps"><code class="xref py py-class docutils literal"><span class="pre">DowngradeOps</span></code></a> objects are appended to these lists. Each <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> and <a class="reference internal" href="operations.html#alembic.operations.ops.DowngradeOps" title="alembic.operations.ops.DowngradeOps"><code class="xref py py-class docutils literal"><span class="pre">DowngradeOps</span></code></a> object maintains an <code class="docutils literal"><span class="pre">.upgrade_token</span></code> and a <code class="docutils literal"><span class="pre">.downgrade_token</span></code> attribute respectively, which serves to render their contents into the appropriate template token.</p> <p>For example, a multi-engine run that has the engine names <code class="docutils literal"><span class="pre">engine1</span></code> and <code class="docutils literal"><span class="pre">engine2</span></code> will generate tokens of <code class="docutils literal"><span class="pre">engine1_upgrades</span></code>, <code class="docutils literal"><span class="pre">engine1_downgrades</span></code>, <code class="docutils literal"><span class="pre">engine2_upgrades</span></code> and <code class="docutils literal"><span class="pre">engine2_downgrades</span></code> as it runs. The resulting migration structure would look like this:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.operations</span> <span class="kn">import</span> <span class="n">ops</span> <span class="kn">import</span> <span class="nn">sqlalchemy</span> <span class="kn">as</span> <span class="nn">sa</span> <span class="n">migration_script</span> <span class="o">=</span> <span class="n">ops</span><span class="o">.</span><span class="n">MigrationScript</span><span class="p">(</span> <span class="s">'eced083f5df'</span><span class="p">,</span> <span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">UpgradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="c"># upgrade operations for "engine1"</span> <span class="p">],</span> <span class="n">upgrade_token</span><span class="o">=</span><span class="s">"engine1_upgrades"</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">UpgradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="c"># upgrade operations for "engine2"</span> <span class="p">],</span> <span class="n">upgrade_token</span><span class="o">=</span><span class="s">"engine2_upgrades"</span> <span class="p">),</span> <span class="p">],</span> <span class="p">[</span> <span class="n">ops</span><span class="o">.</span><span class="n">DowngradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="c"># downgrade operations for "engine1"</span> <span class="p">],</span> <span class="n">downgrade_token</span><span class="o">=</span><span class="s">"engine1_downgrades"</span> <span class="p">),</span> <span class="n">ops</span><span class="o">.</span><span class="n">DowngradeOps</span><span class="p">(</span> <span class="n">ops</span><span class="o">=</span><span class="p">[</span> <span class="c"># downgrade operations for "engine2"</span> <span class="p">],</span> <span class="n">downgrade_token</span><span class="o">=</span><span class="s">"engine2_downgrades"</span> <span class="p">)</span> <span class="p">],</span> <span class="n">message</span><span class="o">=</span><span class="s">'migration message'</span> <span class="p">)</span> </pre></div> </div> <p>Given the above, the following guidelines should be considered when the <code class="docutils literal"><span class="pre">env.py</span></code> script calls upon <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext.run_migrations" title="alembic.runtime.migration.MigrationContext.run_migrations"><code class="xref py py-meth docutils literal"><span class="pre">MigrationContext.run_migrations()</span></code></a> mutiple times when running autogenerate:</p> <ul class="simple"> <li>If the <code class="docutils literal"><span class="pre">process_revision_directives</span></code> hook aims to <strong>add elements based on inspection of the current database / connection</strong>, it should do its operation <strong>on each iteration</strong>. This is so that each time the hook runs, the database is available.</li> <li>Alternatively, if the <code class="docutils literal"><span class="pre">process_revision_directives</span></code> hook aims to <strong>modify the list of migration directives in place</strong>, this should be called <strong>only on the last iteration</strong>. This is so that the hook isn’t being given an ever-growing structure each time which it has already modified previously.</li> <li>The <a class="reference internal" href="#alembic.autogenerate.rewriter.Rewriter" title="alembic.autogenerate.rewriter.Rewriter"><code class="xref py py-class docutils literal"><span class="pre">Rewriter</span></code></a> object, if used, should be called <strong>only on the last iteration</strong>, because it will always deliver all directives every time, so again to avoid double/triple/etc. processing of directives it should be called only when the structure is complete.</li> <li>The <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript.upgrade_ops_list" title="alembic.operations.ops.MigrationScript.upgrade_ops_list"><code class="xref py py-attr docutils literal"><span class="pre">MigrationScript.upgrade_ops_list</span></code></a> and <a class="reference internal" href="operations.html#alembic.operations.ops.MigrationScript.downgrade_ops_list" title="alembic.operations.ops.MigrationScript.downgrade_ops_list"><code class="xref py py-attr docutils literal"><span class="pre">MigrationScript.downgrade_ops_list</span></code></a> attributes should be consulted when referring to the collection of <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> and <a class="reference internal" href="operations.html#alembic.operations.ops.DowngradeOps" title="alembic.operations.ops.DowngradeOps"><code class="xref py py-class docutils literal"><span class="pre">DowngradeOps</span></code></a> objects.</li> </ul> <div class="versionchanged"> <p><span class="versionmodified">Changed in version 0.8.1: </span>- multiple calls to <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext.run_migrations" title="alembic.runtime.migration.MigrationContext.run_migrations"><code class="xref py py-meth docutils literal"><span class="pre">MigrationContext.run_migrations()</span></code></a> within an autogenerate operation, such as that proposed within the <code class="docutils literal"><span class="pre">multidb</span></code> script template, are now accommodated by the new extensible migration system introduced in 0.8.0.</p> </div> </div> </div> <div class="section" id="autogenerating-custom-operation-directives"> <span id="autogen-custom-ops"></span><h2>Autogenerating Custom Operation Directives<a class="headerlink" href="#autogenerating-custom-operation-directives" title="Permalink to this headline">¶</a></h2> <p>In the section <a class="reference internal" href="operations.html#operation-plugins"><span>Operation Plugins</span></a>, we talked about adding new subclasses of <a class="reference internal" href="../ops.html#alembic.operations.MigrateOperation" title="alembic.operations.MigrateOperation"><code class="xref py py-class docutils literal"><span class="pre">MigrateOperation</span></code></a> in order to add new <code class="docutils literal"><span class="pre">op.</span></code> directives. In the preceding section <a class="reference internal" href="#customizing-revision"><span>Customizing Revision Generation</span></a>, we also learned that these same <a class="reference internal" href="../ops.html#alembic.operations.MigrateOperation" title="alembic.operations.MigrateOperation"><code class="xref py py-class docutils literal"><span class="pre">MigrateOperation</span></code></a> structures are at the base of how the autogenerate system knows what Python code to render. Using this knowledge, we can create additional functions that plug into the autogenerate system so that our new operations can be generated into migration scripts when <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span> <span class="pre">--autogenerate</span></code> is run.</p> <p>The following sections will detail an example of this using the the <code class="docutils literal"><span class="pre">CreateSequenceOp</span></code> and <code class="docutils literal"><span class="pre">DropSequenceOp</span></code> directives we created in <a class="reference internal" href="operations.html#operation-plugins"><span>Operation Plugins</span></a>, which correspond to the SQLAlchemy <a class="reference external" href="http://www.sqlalchemy.org/docs/core/defaults.html#sqlalchemy.schema.Sequence" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Sequence</span></code></a> construct.</p> <div class="versionadded"> <p><span class="versionmodified">New in version 0.8.0: </span>- custom operations can be added to the autogenerate system to support new kinds of database objects.</p> </div> <div class="section" id="tracking-our-object-with-the-model"> <h3>Tracking our Object with the Model<a class="headerlink" href="#tracking-our-object-with-the-model" title="Permalink to this headline">¶</a></h3> <p>The basic job of an autogenerate comparison function is to inspect a series of objects in the database and compare them against a series of objects defined in our model. By “in our model”, we mean anything defined in Python code that we want to track, however most commonly we’re talking about a series of <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Table" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Table</span></code></a> objects present in a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> collection.</p> <p>Let’s propose a simple way of seeing what <a class="reference external" href="http://www.sqlalchemy.org/docs/core/defaults.html#sqlalchemy.schema.Sequence" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Sequence</span></code></a> objects we want to ensure exist in the database when autogenerate runs. While these objects do have some integrations with <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Table" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Table</span></code></a> and <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> already, let’s assume they don’t, as the example here intends to illustrate how we would do this for most any kind of custom construct. We associate the object with the <code class="xref py py-attr docutils literal"><span class="pre">info</span></code> collection of <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a>, which is a dictionary we can use for anything, which we also know will be passed to the autogenerate process:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy.schema</span> <span class="kn">import</span> <span class="n">Sequence</span> <span class="k">def</span> <span class="nf">add_sequence_to_model</span><span class="p">(</span><span class="n">sequence</span><span class="p">,</span> <span class="n">metadata</span><span class="p">):</span> <span class="n">metadata</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s">"sequences"</span><span class="p">,</span> <span class="nb">set</span><span class="p">())</span><span class="o">.</span><span class="n">add</span><span class="p">(</span> <span class="p">(</span><span class="n">sequence</span><span class="o">.</span><span class="n">schema</span><span class="p">,</span> <span class="n">sequence</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="p">)</span> <span class="n">my_seq</span> <span class="o">=</span> <span class="n">Sequence</span><span class="p">(</span><span class="s">"my_sequence"</span><span class="p">)</span> <span class="n">add_sequence_to_model</span><span class="p">(</span><span class="n">my_seq</span><span class="p">,</span> <span class="n">model_metadata</span><span class="p">)</span> </pre></div> </div> <p>The <code class="xref py py-attr docutils literal"><span class="pre">info</span></code> dictionary is a good place to put things that we want our autogeneration routines to be able to locate, which can include any object such as custom DDL objects representing views, triggers, special constraints, or anything else we want to support.</p> </div> <div class="section" id="registering-a-comparison-function"> <h3>Registering a Comparison Function<a class="headerlink" href="#registering-a-comparison-function" title="Permalink to this headline">¶</a></h3> <p>We now need to register a comparison hook, which will be used to compare the database to our model and produce <code class="docutils literal"><span class="pre">CreateSequenceOp</span></code> and <code class="docutils literal"><span class="pre">DropSequenceOp</span></code> directives to be included in our migration script. Note that we are assuming a Postgresql backend:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.autogenerate</span> <span class="kn">import</span> <span class="n">comparators</span> <span class="nd">@comparators.dispatch_for</span><span class="p">(</span><span class="s">"schema"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">compare_sequences</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">upgrade_ops</span><span class="p">,</span> <span class="n">schemas</span><span class="p">):</span> <span class="n">all_conn_sequences</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">sch</span> <span class="ow">in</span> <span class="n">schemas</span><span class="p">:</span> <span class="n">all_conn_sequences</span><span class="o">.</span><span class="n">update</span><span class="p">([</span> <span class="p">(</span><span class="n">sch</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">autogen_context</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span> <span class="s">"SELECT relname FROM pg_class c join "</span> <span class="s">"pg_namespace n on n.oid=c.relnamespace where "</span> <span class="s">"relkind='S' and n.nspname=</span><span class="si">%(nspname)s</span><span class="s">"</span><span class="p">,</span> <span class="c"># note that we consider a schema of 'None' in our</span> <span class="c"># model to be the "default" name in the PG database;</span> <span class="c"># this usually is the name 'public'</span> <span class="n">nspname</span><span class="o">=</span><span class="n">autogen_context</span><span class="o">.</span><span class="n">dialect</span><span class="o">.</span><span class="n">default_schema_name</span> <span class="k">if</span> <span class="n">sch</span> <span class="ow">is</span> <span class="bp">None</span> <span class="k">else</span> <span class="n">sch</span> <span class="p">)</span> <span class="p">])</span> <span class="c"># get the collection of Sequence objects we're storing with</span> <span class="c"># our MetaData</span> <span class="n">metadata_sequences</span> <span class="o">=</span> <span class="n">autogen_context</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span> <span class="s">"sequences"</span><span class="p">,</span> <span class="nb">set</span><span class="p">())</span> <span class="c"># for new names, produce CreateSequenceOp directives</span> <span class="k">for</span> <span class="n">sch</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">metadata_sequences</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">all_conn_sequences</span><span class="p">):</span> <span class="n">upgrade_ops</span><span class="o">.</span><span class="n">ops</span><span class="o">.</span><span class="n">append</span><span class="p">(</span> <span class="n">CreateSequenceOp</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">sch</span><span class="p">)</span> <span class="p">)</span> <span class="c"># for names that are going away, produce DropSequenceOp</span> <span class="c"># directives</span> <span class="k">for</span> <span class="n">sch</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">all_conn_sequences</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">metadata_sequences</span><span class="p">):</span> <span class="n">upgrade_ops</span><span class="o">.</span><span class="n">ops</span><span class="o">.</span><span class="n">append</span><span class="p">(</span> <span class="n">DropSequenceOp</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">sch</span><span class="p">)</span> <span class="p">)</span> </pre></div> </div> <p>Above, we’ve built a new function <code class="docutils literal"><span class="pre">compare_sequences()</span></code> and registered it as a “schema” level comparison function with autogenerate. The job that it performs is that it compares the list of sequence names present in each database schema with that of a list of sequence names that we are maintaining in our <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> object.</p> <p>When autogenerate completes, it will have a series of <code class="docutils literal"><span class="pre">CreateSequenceOp</span></code> and <code class="docutils literal"><span class="pre">DropSequenceOp</span></code> directives in the list of “upgrade” operations; the list of “downgrade” operations is generated directly from these using the <code class="docutils literal"><span class="pre">CreateSequenceOp.reverse()</span></code> and <code class="docutils literal"><span class="pre">DropSequenceOp.reverse()</span></code> methods that we’ve implemented on these objects.</p> <p>The registration of our function at the scope of “schema” means our autogenerate comparison function is called outside of the context of any specific table or column. The three available scopes are “schema”, “table”, and “column”, summarized as follows:</p> <ul> <li><p class="first"><strong>Schema level</strong> - these hooks are passed a <a class="reference internal" href="#alembic.autogenerate.api.AutogenContext" title="alembic.autogenerate.api.AutogenContext"><code class="xref py py-class docutils literal"><span class="pre">AutogenContext</span></code></a>, an <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> collection, and a collection of string schema names to be operated upon. If the <a class="reference internal" href="operations.html#alembic.operations.ops.UpgradeOps" title="alembic.operations.ops.UpgradeOps"><code class="xref py py-class docutils literal"><span class="pre">UpgradeOps</span></code></a> collection contains changes after all hooks are run, it is included in the migration script:</p> <div class="highlight-python"><div class="highlight"><pre><span class="nd">@comparators.dispatch_for</span><span class="p">(</span><span class="s">"schema"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">compare_schema_level</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">upgrade_ops</span><span class="p">,</span> <span class="n">schemas</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> </li> <li><p class="first"><strong>Table level</strong> - these hooks are passed a <a class="reference internal" href="#alembic.autogenerate.api.AutogenContext" title="alembic.autogenerate.api.AutogenContext"><code class="xref py py-class docutils literal"><span class="pre">AutogenContext</span></code></a>, a <a class="reference internal" href="operations.html#alembic.operations.ops.ModifyTableOps" title="alembic.operations.ops.ModifyTableOps"><code class="xref py py-class docutils literal"><span class="pre">ModifyTableOps</span></code></a> collection, a schema name, table name, a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Table" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Table</span></code></a> reflected from the database if any or <code class="docutils literal"><span class="pre">None</span></code>, and a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Table" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Table</span></code></a> present in the local <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a>. If the <a class="reference internal" href="operations.html#alembic.operations.ops.ModifyTableOps" title="alembic.operations.ops.ModifyTableOps"><code class="xref py py-class docutils literal"><span class="pre">ModifyTableOps</span></code></a> collection contains changes after all hooks are run, it is included in the migration script:</p> <div class="highlight-python"><div class="highlight"><pre><span class="nd">@comparators.dispatch_for</span><span class="p">(</span><span class="s">"table"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">compare_table_level</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">modify_ops</span><span class="p">,</span> <span class="n">schemaname</span><span class="p">,</span> <span class="n">tablename</span><span class="p">,</span> <span class="n">conn_table</span><span class="p">,</span> <span class="n">metadata_table</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> </li> <li><p class="first"><strong>Column level</strong> - these hooks are passed a <a class="reference internal" href="#alembic.autogenerate.api.AutogenContext" title="alembic.autogenerate.api.AutogenContext"><code class="xref py py-class docutils literal"><span class="pre">AutogenContext</span></code></a>, an <a class="reference internal" href="operations.html#alembic.operations.ops.AlterColumnOp" title="alembic.operations.ops.AlterColumnOp"><code class="xref py py-class docutils literal"><span class="pre">AlterColumnOp</span></code></a> object, a schema name, table name, column name, a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Column" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Column</span></code></a> reflected from the database and a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Column" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Column</span></code></a> present in the local table. If the <a class="reference internal" href="operations.html#alembic.operations.ops.AlterColumnOp" title="alembic.operations.ops.AlterColumnOp"><code class="xref py py-class docutils literal"><span class="pre">AlterColumnOp</span></code></a> contains changes after all hooks are run, it is included in the migration script; a “change” is considered to be present if any of the <code class="docutils literal"><span class="pre">modify_</span></code> attributes are set to a non-default value, or there are any keys in the <code class="docutils literal"><span class="pre">.kw</span></code> collection with the prefix <code class="docutils literal"><span class="pre">"modify_"</span></code>:</p> <div class="highlight-python"><div class="highlight"><pre><span class="nd">@comparators.dispatch_for</span><span class="p">(</span><span class="s">"column"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">compare_column_level</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">alter_column_op</span><span class="p">,</span> <span class="n">schemaname</span><span class="p">,</span> <span class="n">tname</span><span class="p">,</span> <span class="n">cname</span><span class="p">,</span> <span class="n">conn_col</span><span class="p">,</span> <span class="n">metadata_col</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> </li> </ul> <p>The <a class="reference internal" href="#alembic.autogenerate.api.AutogenContext" title="alembic.autogenerate.api.AutogenContext"><code class="xref py py-class docutils literal"><span class="pre">AutogenContext</span></code></a> passed to these hooks is documented below.</p> <dl class="class"> <dt id="alembic.autogenerate.api.AutogenContext"> <em class="property">class </em><code class="descclassname">alembic.autogenerate.api.</code><code class="descname">AutogenContext</code><span class="sig-paren">(</span><em>migration_context</em>, <em>metadata=None</em>, <em>opts=None</em>, <em>autogenerate=True</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext" title="Permalink to this definition">¶</a></dt> <dd><p>Maintains configuration and state that’s specific to an autogenerate operation.</p> <dl class="attribute"> <dt id="alembic.autogenerate.api.AutogenContext.connection"> <code class="descname">connection</code><em class="property"> = None</em><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.connection" title="Permalink to this definition">¶</a></dt> <dd><p>The <code class="xref py py-class docutils literal"><span class="pre">Connection</span></code> object currently connected to the database backend being compared.</p> <p>This is obtained from the <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext.bind" title="alembic.runtime.migration.MigrationContext.bind"><code class="xref py py-attr docutils literal"><span class="pre">MigrationContext.bind</span></code></a> and is utimately set up in the <code class="docutils literal"><span class="pre">env.py</span></code> script.</p> </dd></dl> <dl class="attribute"> <dt id="alembic.autogenerate.api.AutogenContext.dialect"> <code class="descname">dialect</code><em class="property"> = None</em><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.dialect" title="Permalink to this definition">¶</a></dt> <dd><p>The <code class="xref py py-class docutils literal"><span class="pre">Dialect</span></code> object currently in use.</p> <p>This is normally obtained from the <code class="xref py py-attr docutils literal"><span class="pre">dialect</span></code> attribute.</p> </dd></dl> <dl class="attribute"> <dt id="alembic.autogenerate.api.AutogenContext.imports"> <code class="descname">imports</code><em class="property"> = None</em><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.imports" title="Permalink to this definition">¶</a></dt> <dd><p>A <code class="docutils literal"><span class="pre">set()</span></code> which contains string Python import directives.</p> <p>The directives are to be rendered into the <code class="docutils literal"><span class="pre">${imports}</span></code> section of a script template. The set is normally empty and can be modified within hooks such as the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.render_item" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.render_item</span></code></a> hook.</p> <div class="versionadded"> <p><span class="versionmodified">New in version 0.8.3.</span></p> </div> <div class="admonition seealso"> <p class="first admonition-title">See also</p> <p class="last"><a class="reference internal" href="../autogenerate.html#autogen-render-types"><span>Affecting the Rendering of Types Themselves</span></a></p> </div> </dd></dl> <dl class="attribute"> <dt id="alembic.autogenerate.api.AutogenContext.metadata"> <code class="descname">metadata</code><em class="property"> = None</em><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.metadata" title="Permalink to this definition">¶</a></dt> <dd><p>The <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> object representing the destination.</p> <p>This object is the one that is passed within <code class="docutils literal"><span class="pre">env.py</span></code> to the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.target_metadata" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.target_metadata</span></code></a> parameter. It represents the structure of <code class="xref py py-class docutils literal"><span class="pre">Table</span></code> and other objects as stated in the current database model, and represents the destination structure for the database being examined.</p> <p>While the <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.MetaData" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">MetaData</span></code></a> object is primarily known as a collection of <a class="reference external" href="http://www.sqlalchemy.org/docs/core/metadata.html#sqlalchemy.schema.Table" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Table</span></code></a> objects, it also has an <code class="xref py py-attr docutils literal"><span class="pre">info</span></code> dictionary that may be used by end-user schemes to store additional schema-level objects that are to be compared in custom autogeneration schemes.</p> </dd></dl> <dl class="attribute"> <dt id="alembic.autogenerate.api.AutogenContext.migration_context"> <code class="descname">migration_context</code><em class="property"> = None</em><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.migration_context" title="Permalink to this definition">¶</a></dt> <dd><p>The <a class="reference internal" href="runtime.html#alembic.runtime.migration.MigrationContext" title="alembic.runtime.migration.MigrationContext"><code class="xref py py-class docutils literal"><span class="pre">MigrationContext</span></code></a> established by the <code class="docutils literal"><span class="pre">env.py</span></code> script.</p> </dd></dl> <dl class="method"> <dt id="alembic.autogenerate.api.AutogenContext.run_filters"> <code class="descname">run_filters</code><span class="sig-paren">(</span><em>object_</em>, <em>name</em>, <em>type_</em>, <em>reflected</em>, <em>compare_to</em><span class="sig-paren">)</span><a class="headerlink" href="#alembic.autogenerate.api.AutogenContext.run_filters" title="Permalink to this definition">¶</a></dt> <dd><p>Run the context’s object filters and return True if the targets should be part of the autogenerate operation.</p> <p>This method should be run for every kind of object encountered within an autogenerate operation, giving the environment the chance to filter what objects should be included in the comparison. The filters here are produced directly via the <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.include_object" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.include_object</span></code></a> and <a class="reference internal" href="runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.include_symbol" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.include_symbol</span></code></a> functions, if present.</p> </dd></dl> </dd></dl> </div> <div class="section" id="creating-a-render-function"> <h3>Creating a Render Function<a class="headerlink" href="#creating-a-render-function" title="Permalink to this headline">¶</a></h3> <p>The second autogenerate integration hook is to provide a “render” function; since the autogenerate system renders Python code, we need to build a function that renders the correct “op” instructions for our directive:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">alembic.autogenerate</span> <span class="kn">import</span> <span class="n">renderers</span> <span class="nd">@renderers.dispatch_for</span><span class="p">(</span><span class="n">CreateSequenceOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">render_create_sequence</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="k">return</span> <span class="s">"op.create_sequence(</span><span class="si">%r</span><span class="s">, **</span><span class="si">%r</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span> <span class="n">op</span><span class="o">.</span><span class="n">sequence_name</span><span class="p">,</span> <span class="p">{</span><span class="s">"schema"</span><span class="p">:</span> <span class="n">op</span><span class="o">.</span><span class="n">schema</span><span class="p">}</span> <span class="p">)</span> <span class="nd">@renderers.dispatch_for</span><span class="p">(</span><span class="n">DropSequenceOp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">render_drop_sequence</span><span class="p">(</span><span class="n">autogen_context</span><span class="p">,</span> <span class="n">op</span><span class="p">):</span> <span class="k">return</span> <span class="s">"op.drop_sequence(</span><span class="si">%r</span><span class="s">, **</span><span class="si">%r</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span> <span class="n">op</span><span class="o">.</span><span class="n">sequence_name</span><span class="p">,</span> <span class="p">{</span><span class="s">"schema"</span><span class="p">:</span> <span class="n">op</span><span class="o">.</span><span class="n">schema</span><span class="p">}</span> <span class="p">)</span> </pre></div> </div> <p>The above functions will render Python code corresponding to the presence of <code class="docutils literal"><span class="pre">CreateSequenceOp</span></code> and <code class="docutils literal"><span class="pre">DropSequenceOp</span></code> instructions in the list that our comparison function generates.</p> </div> <div class="section" id="running-it"> <h3>Running It<a class="headerlink" href="#running-it" title="Permalink to this headline">¶</a></h3> <p>All the above code can be organized however the developer sees fit; the only thing that needs to make it work is that when the Alembic environment <code class="docutils literal"><span class="pre">env.py</span></code> is invoked, it either imports modules which contain all the above routines, or they are locally present, or some combination thereof.</p> <p>If we then have code in our model (which of course also needs to be invoked when <code class="docutils literal"><span class="pre">env.py</span></code> runs!) like this:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy.schema</span> <span class="kn">import</span> <span class="n">Sequence</span> <span class="n">my_seq_1</span> <span class="o">=</span> <span class="n">Sequence</span><span class="p">(</span><span class="s">"my_sequence_1"</span><span class="p">)</span> <span class="n">add_sequence_to_model</span><span class="p">(</span><span class="n">my_seq_1</span><span class="p">,</span> <span class="n">target_metadata</span><span class="p">)</span> </pre></div> </div> <p>When we first run <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">revision</span> <span class="pre">--autogenerate</span></code>, we’ll see this in our migration file:</p> <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">upgrade</span><span class="p">():</span> <span class="c">### commands auto generated by Alembic - please adjust! ###</span> <span class="n">op</span><span class="o">.</span><span class="n">create_sequence</span><span class="p">(</span><span class="s">'my_sequence_1'</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="s">'schema'</span><span class="p">:</span> <span class="bp">None</span><span class="p">})</span> <span class="c">### end Alembic commands ###</span> <span class="k">def</span> <span class="nf">downgrade</span><span class="p">():</span> <span class="c">### commands auto generated by Alembic - please adjust! ###</span> <span class="n">op</span><span class="o">.</span><span class="n">drop_sequence</span><span class="p">(</span><span class="s">'my_sequence_1'</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="s">'schema'</span><span class="p">:</span> <span class="bp">None</span><span class="p">})</span> <span class="c">### end Alembic commands ###</span> </pre></div> </div> <p>These are our custom directives that will invoke when <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">upgrade</span></code> or <code class="docutils literal"><span class="pre">alembic</span> <span class="pre">downgrade</span></code> is run.</p> </div> </div> </div> </div> </div> </div> <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> <div class="sphinxsidebarwrapper"> <h3><a href="../index.html">Table Of Contents</a></h3> <ul> <li><a class="reference internal" href="#">Autogeneration</a><ul> <li><a class="reference internal" href="#getting-diffs">Getting Diffs</a></li> <li><a class="reference internal" href="#customizing-revision-generation">Customizing Revision Generation</a><ul> <li><a class="reference internal" href="#fine-grained-autogenerate-generation-with-rewriters">Fine-Grained Autogenerate Generation with Rewriters</a></li> <li><a class="reference internal" href="#revision-generation-with-multiple-engines-run-migrations-calls">Revision Generation with Multiple Engines / <code class="docutils literal"><span class="pre">run_migrations()</span></code> calls</a></li> </ul> </li> <li><a class="reference internal" href="#autogenerating-custom-operation-directives">Autogenerating Custom Operation Directives</a><ul> <li><a class="reference internal" href="#tracking-our-object-with-the-model">Tracking our Object with the Model</a></li> <li><a class="reference internal" href="#registering-a-comparison-function">Registering a Comparison Function</a></li> <li><a class="reference internal" href="#creating-a-render-function">Creating a Render Function</a></li> <li><a class="reference internal" href="#running-it">Running It</a></li> </ul> </li> </ul> </li> </ul> <h4>Previous topic</h4> <p class="topless"><a href="operations.html" title="previous chapter">Operation Directives</a></p> <h4>Next topic</h4> <p class="topless"><a href="script.html" title="next chapter">Script Directory</a></p> <div role="note" aria-label="source link"> <h3>This Page</h3> <ul class="this-page-menu"> <li><a href="../_sources/api/autogenerate.txt" rel="nofollow">Show Source</a></li> </ul> </div> <div id="searchbox" style="display: none" role="search"> <h3>Quick search</h3> <form class="search" action="../search.html" method="get"> <input type="text" name="q" /> <input type="submit" value="Go" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> <p class="searchtip" style="font-size: 90%"> Enter search terms or a module, class or function name. </p> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <div class="clearer"></div> </div> <div class="related" role="navigation" aria-label="related navigation"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../genindex.html" title="General Index" >index</a></li> <li class="right" > <a href="../py-modindex.html" title="Python Module Index" >modules</a> |</li> <li class="right" > <a href="script.html" title="Script Directory" >next</a> |</li> <li class="right" > <a href="operations.html" title="Operation Directives" >previous</a> |</li> <li class="nav-item nav-item-0"><a href="../index.html">Alembic 0.8.3 documentation</a> »</li> <li class="nav-item nav-item-1"><a href="index.html" >API Details</a> »</li> </ul> </div> <div class="footer" role="contentinfo"> © Copyright 2010-2015, Mike Bayer. Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.3.1. </div> </body> </html>