Loading docs/howto/writing-migrations.txt +54 −31 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ Then, to leverage this in your migrations, do the following:: def forwards(apps, schema_editor): # Your migration code goes here ... class Migration(migrations.Migration): Loading @@ -83,44 +84,76 @@ Therefore, the following steps should be taken. In this example, we'll add a non-nullable :class:`~django.db.models.UUIDField` with a default value. Modify the respective field according to your needs. * Add the field on your model with ``default=...`` and ``unique=True`` arguments. In the example, we use ``uuid.uuid4`` for the default. * Add the field on your model with ``default=uuid.uuid4`` and ``unique=True`` arguments (choose an appropriate default for the type of the field you're adding). * Run the :djadmin:`makemigrations` command. * Run the :djadmin:`makemigrations` command. This should generate a migration with an ``AddField`` operation. * Edit the created migration file. * Generate two empty migration files for the same app by running ``makemigrations myapp --empty`` twice. We've renamed the migration files to give them meaningful names in the examples below. * Copy the ``AddField`` operation from the auto-generated migration (the first of the three new files) to the last migration and change ``AddField`` to ``AlterField``. For example: .. snippet:: :filename: 0006_remove_uuid_null.py # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import migrations, models import uuid The generated migration class should look similar to this:: class Migration(migrations.Migration): dependencies = [ ('myapp', '0003_auto_20150129_1705'), ('myapp', '0005_populate_uuid_values'), ] operations = [ migrations.AddField( migrations.AlterField( model_name='mymodel', name='uuid', field=models.UUIDField(max_length=32, unique=True, default=uuid.uuid4), field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] You will need to make three changes: * Edit the first migration file. The generated migration class should look similar to this: .. snippet:: :filename: 0004_add_uuid_field.py * Add a second :class:`~django.db.migrations.operations.AddField` operation copied from the generated one and change it to :class:`~django.db.migrations.operations.AlterField`. class Migration(migrations.Migration): * On the first operation (``AddField``), change ``unique=True`` to ``null=True`` -- this will create the intermediary null field. dependencies = [ ('myapp', '0003_auto_20150129_1705'), ] * Between the two operations, add a operations = [ migrations.AddField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] Change ``unique=True`` to ``null=True`` -- this will create the intermediary null field and defer creating the unique constraint until we've populated unique values on all the rows. * In the first empty migration file, add a :class:`~django.db.migrations.operations.RunPython` or :class:`~django.db.migrations.operations.RunSQL` operation to generate a unique value (UUID in the example) for each existing row. unique value (UUID in the example) for each existing row. For example: The resulting migration should look similar to this:: .. snippet:: :filename: 0005_populate_uuid_values.py # -*- coding: utf-8 -*- from __future__ import unicode_literals Loading @@ -137,25 +170,15 @@ the respective field according to your needs. class Migration(migrations.Migration): dependencies = [ ('myapp', '0003_auto_20150129_1705'), ('myapp', '0004_add_uuid_field'), ] operations = [ migrations.AddField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, null=True), ), # omit reverse_code=... if you don't want the migration to be reversible. migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop), migrations.AlterField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] * Now you can apply the migration as usual with the :djadmin:`migrate` command. * Now you can apply the migrations as usual with the :djadmin:`migrate` command. Note there is a race condition if you allow objects to be created while this migration is running. Objects created after the ``AddField`` and before Loading docs/ref/migration-operations.txt +16 −4 Original line number Diff line number Diff line Loading @@ -322,11 +322,23 @@ or that you use :class:`SeparateDatabaseAndState` to add in operations that will reflect your changes to the model state - otherwise, the versioned ORM and the autodetector will stop working correctly. By default, ``RunPython`` will run its contents inside a transaction even on databases that do not support DDL transactions (for example, MySQL and By default, ``RunPython`` will run its contents inside a transaction on databases that do not support DDL transactions (for example, MySQL and Oracle). This should be safe, but may cause a crash if you attempt to use the ``schema_editor`` provided on these backends; in this case, please set ``atomic=False``. the ``schema_editor`` provided on these backends; in this case, pass ``atomic=False`` to the ``RunPython`` operation. 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``. 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. .. warning:: Loading Loading
docs/howto/writing-migrations.txt +54 −31 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ Then, to leverage this in your migrations, do the following:: def forwards(apps, schema_editor): # Your migration code goes here ... class Migration(migrations.Migration): Loading @@ -83,44 +84,76 @@ Therefore, the following steps should be taken. In this example, we'll add a non-nullable :class:`~django.db.models.UUIDField` with a default value. Modify the respective field according to your needs. * Add the field on your model with ``default=...`` and ``unique=True`` arguments. In the example, we use ``uuid.uuid4`` for the default. * Add the field on your model with ``default=uuid.uuid4`` and ``unique=True`` arguments (choose an appropriate default for the type of the field you're adding). * Run the :djadmin:`makemigrations` command. * Run the :djadmin:`makemigrations` command. This should generate a migration with an ``AddField`` operation. * Edit the created migration file. * Generate two empty migration files for the same app by running ``makemigrations myapp --empty`` twice. We've renamed the migration files to give them meaningful names in the examples below. * Copy the ``AddField`` operation from the auto-generated migration (the first of the three new files) to the last migration and change ``AddField`` to ``AlterField``. For example: .. snippet:: :filename: 0006_remove_uuid_null.py # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import migrations, models import uuid The generated migration class should look similar to this:: class Migration(migrations.Migration): dependencies = [ ('myapp', '0003_auto_20150129_1705'), ('myapp', '0005_populate_uuid_values'), ] operations = [ migrations.AddField( migrations.AlterField( model_name='mymodel', name='uuid', field=models.UUIDField(max_length=32, unique=True, default=uuid.uuid4), field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] You will need to make three changes: * Edit the first migration file. The generated migration class should look similar to this: .. snippet:: :filename: 0004_add_uuid_field.py * Add a second :class:`~django.db.migrations.operations.AddField` operation copied from the generated one and change it to :class:`~django.db.migrations.operations.AlterField`. class Migration(migrations.Migration): * On the first operation (``AddField``), change ``unique=True`` to ``null=True`` -- this will create the intermediary null field. dependencies = [ ('myapp', '0003_auto_20150129_1705'), ] * Between the two operations, add a operations = [ migrations.AddField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] Change ``unique=True`` to ``null=True`` -- this will create the intermediary null field and defer creating the unique constraint until we've populated unique values on all the rows. * In the first empty migration file, add a :class:`~django.db.migrations.operations.RunPython` or :class:`~django.db.migrations.operations.RunSQL` operation to generate a unique value (UUID in the example) for each existing row. unique value (UUID in the example) for each existing row. For example: The resulting migration should look similar to this:: .. snippet:: :filename: 0005_populate_uuid_values.py # -*- coding: utf-8 -*- from __future__ import unicode_literals Loading @@ -137,25 +170,15 @@ the respective field according to your needs. class Migration(migrations.Migration): dependencies = [ ('myapp', '0003_auto_20150129_1705'), ('myapp', '0004_add_uuid_field'), ] operations = [ migrations.AddField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, null=True), ), # omit reverse_code=... if you don't want the migration to be reversible. migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop), migrations.AlterField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] * Now you can apply the migration as usual with the :djadmin:`migrate` command. * Now you can apply the migrations as usual with the :djadmin:`migrate` command. Note there is a race condition if you allow objects to be created while this migration is running. Objects created after the ``AddField`` and before Loading
docs/ref/migration-operations.txt +16 −4 Original line number Diff line number Diff line Loading @@ -322,11 +322,23 @@ or that you use :class:`SeparateDatabaseAndState` to add in operations that will reflect your changes to the model state - otherwise, the versioned ORM and the autodetector will stop working correctly. By default, ``RunPython`` will run its contents inside a transaction even on databases that do not support DDL transactions (for example, MySQL and By default, ``RunPython`` will run its contents inside a transaction on databases that do not support DDL transactions (for example, MySQL and Oracle). This should be safe, but may cause a crash if you attempt to use the ``schema_editor`` provided on these backends; in this case, please set ``atomic=False``. the ``schema_editor`` provided on these backends; in this case, pass ``atomic=False`` to the ``RunPython`` operation. 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``. 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. .. warning:: Loading