mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #25833 -- Added support for non-atomic migrations.
Added the Migration.atomic attribute which can be set to False for non-atomic migrations.
This commit is contained in:
parent
0edb8a146f
commit
f91a04621e
14 changed files with 181 additions and 16 deletions
|
@ -184,6 +184,53 @@ the respective field according to your needs.
|
|||
migration is running. Objects created after the ``AddField`` and before
|
||||
``RunPython`` will have their original ``uuid``’s overwritten.
|
||||
|
||||
.. _non-atomic-migrations:
|
||||
|
||||
Non-atomic migrations
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 1.10
|
||||
|
||||
On databases that support DDL transactions (SQLite and PostgreSQL), migrations
|
||||
will run inside a transaction by default. For use cases such as performing data
|
||||
migrations on large tables, you may want to prevent a migration from running in
|
||||
a transaction by setting the ``atomic`` attribute to ``False``::
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
Within such a migration, all operations are run without a transaction. It's
|
||||
possible to execute parts of the migration inside a transaction using
|
||||
:func:`~django.db.transaction.atomic()` or by passing ``atomic=True`` to
|
||||
``RunPython``.
|
||||
|
||||
Here's an example of a non-atomic data migration that updates a large table in
|
||||
smaller batches::
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import migrations, transaction
|
||||
|
||||
def gen_uuid(apps, schema_editor):
|
||||
MyModel = apps.get_model('myapp', 'MyModel')
|
||||
while MyModel.objects.filter(uuid__isnull=True).exists():
|
||||
with transaction.atomic():
|
||||
for row in MyModel.objects.filter(uuid__isnull=True)[:1000]:
|
||||
row.uuid = uuid.uuid4()
|
||||
row.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(gen_uuid),
|
||||
]
|
||||
|
||||
The ``atomic`` attribute doesn't have an effect on databases that don't support
|
||||
DDL transactions (e.g. MySQL, Oracle).
|
||||
|
||||
Controlling the order of migrations
|
||||
===================================
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ be removed (elided) when :ref:`squashing migrations <migration-squashing>`.
|
|||
``RunPython``
|
||||
-------------
|
||||
|
||||
.. class:: RunPython(code, reverse_code=None, atomic=True, hints=None, elidable=False)
|
||||
.. class:: RunPython(code, reverse_code=None, atomic=None, hints=None, elidable=False)
|
||||
|
||||
Runs custom Python code in a historical context. ``code`` (and ``reverse_code``
|
||||
if supplied) should be callable objects that accept two arguments; the first is
|
||||
|
@ -354,16 +354,19 @@ the ``schema_editor`` provided on these backends; in this case, pass
|
|||
|
||||
On databases that do support DDL transactions (SQLite and PostgreSQL),
|
||||
``RunPython`` operations do not have any transactions automatically added
|
||||
besides the transactions created for each migration (the ``atomic`` parameter
|
||||
has no effect on these databases). Thus, on PostgreSQL, for example, you should
|
||||
avoid combining schema changes and ``RunPython`` operations in the same
|
||||
migration or you may hit errors like ``OperationalError: cannot ALTER TABLE
|
||||
"mytable" because it has pending trigger events``.
|
||||
besides the transactions created for each migration. Thus, on PostgreSQL, for
|
||||
example, you should avoid combining schema changes and ``RunPython`` operations
|
||||
in the same migration or you may hit errors like ``OperationalError: cannot
|
||||
ALTER TABLE "mytable" because it has pending trigger events``.
|
||||
|
||||
If you have a different database and aren't sure if it supports DDL
|
||||
transactions, check the ``django.db.connection.features.can_rollback_ddl``
|
||||
attribute.
|
||||
|
||||
If the ``RunPython`` operation is part of a :ref:`non-atomic migration
|
||||
<non-atomic-migrations>`, the operation will only be executed in a transaction
|
||||
if ``atomic=True`` is passed to the ``RunPython`` operation.
|
||||
|
||||
.. warning::
|
||||
|
||||
``RunPython`` does not magically alter the connection of the models for you;
|
||||
|
@ -382,6 +385,11 @@ attribute.
|
|||
|
||||
The ``elidable`` argument was added.
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
The ``atomic`` argument default was changed to ``None``, indicating that
|
||||
the atomicity is controlled by the ``atomic`` attribute of the migration.
|
||||
|
||||
``SeparateDatabaseAndState``
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -258,6 +258,9 @@ Migrations
|
|||
:class:`~django.db.migrations.operations.RunPython` operations to allow them
|
||||
to be removed when squashing migrations.
|
||||
|
||||
* Added support for :ref:`non-atomic migrations <non-atomic-migrations>` by
|
||||
setting the ``atomic`` attribute on a ``Migration``.
|
||||
|
||||
Models
|
||||
~~~~~~
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue