mirror of
				https://github.com/django/django.git
				synced 2025-10-28 08:06:09 +00:00 
			
		
		
		
	The new signature enables better support for routing RunPython and
RunSQL operations, especially w.r.t. reusable and third-party apps.
This commit also takes advantage of the deprecation cycle for the old
signature to remove the backward incompatibility introduced in #22583;
RunPython and RunSQL won't call allow_migrate() when when the router
has the old signature.
Thanks Aymeric Augustin and Tim Graham for helping shape up the patch.
Refs 22583.
Conflicts:
	django/db/utils.py
Backport of bed504d70b from master
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ===========================
 | ||
| Writing database migrations
 | ||
| ===========================
 | ||
| 
 | ||
| This document explains how to structure and write database migrations for
 | ||
| different scenarios you might encounter. For introductory material on
 | ||
| migrations, see :doc:`the topic guide </topics/migrations>`.
 | ||
| 
 | ||
| .. _data-migrations-and-multiple-databases:
 | ||
| 
 | ||
| Data migrations and multiple databases
 | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| When using multiple databases, you may need to figure out whether or not to
 | ||
| run a migration against a particular database. For example, you may want to
 | ||
| **only** run a migration on a particular database.
 | ||
| 
 | ||
| In order to do that you can check the database connection's alias inside a
 | ||
| ``RunPython`` operation by looking at the ``schema_editor.connection.alias``
 | ||
| attribute::
 | ||
| 
 | ||
|     from django.db import migrations
 | ||
| 
 | ||
|     def forwards(apps, schema_editor):
 | ||
|         if not schema_editor.connection.alias == 'default':
 | ||
|             return
 | ||
|         # Your migration code goes here
 | ||
| 
 | ||
|     class Migration(migrations.Migration):
 | ||
| 
 | ||
|         dependencies = [
 | ||
|             # Dependencies to other migrations
 | ||
|         ]
 | ||
| 
 | ||
|         operations = [
 | ||
|             migrations.RunPython(forwards),
 | ||
|         ]
 | ||
| 
 | ||
| .. versionadded:: 1.8
 | ||
| 
 | ||
| You can also provide hints that will be passed to the :meth:`allow_migrate()`
 | ||
| method of database routers as ``**hints``:
 | ||
| 
 | ||
| .. snippet::
 | ||
|     :filename: myapp/dbrouters.py
 | ||
| 
 | ||
|     class MyRouter(object):
 | ||
| 
 | ||
|         def allow_migrate(self, db, app_label, model_name=None, **hints):
 | ||
|             if 'target_db' in hints:
 | ||
|                 return db == hints['target_db']
 | ||
|             return True
 | ||
| 
 | ||
| Then, to leverage this in your migrations, do the following::
 | ||
| 
 | ||
|     from django.db import migrations
 | ||
| 
 | ||
|     def forwards(apps, schema_editor):
 | ||
|         # Your migration code goes here
 | ||
| 
 | ||
|     class Migration(migrations.Migration):
 | ||
| 
 | ||
|         dependencies = [
 | ||
|             # Dependencies to other migrations
 | ||
|         ]
 | ||
| 
 | ||
|         operations = [
 | ||
|             migrations.RunPython(forwards, hints={'target_db': 'default'}),
 | ||
|         ]
 | ||
| 
 | ||
| If your ``RunPython`` or ``RunSQL`` operation only affects one model, it's good
 | ||
| practice to pass ``model_name`` as a hint to make it as transparent as possible
 | ||
| to the router. This is especially important for reusable and third-party apps.
 | ||
| 
 | ||
| Migrations that add unique fields
 | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| Applying a "plain" migration that adds a unique non-nullable field to a table
 | ||
| with existing rows will raise an error because the value used to populate
 | ||
| existing rows is generated only once, thus breaking the unique constraint.
 | ||
| 
 | ||
| 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.
 | ||
| 
 | ||
| * Run the :djadmin:`makemigrations` command.
 | ||
| 
 | ||
| * Edit the created migration file.
 | ||
| 
 | ||
|   The generated migration class should look similar to this::
 | ||
| 
 | ||
|     class Migration(migrations.Migration):
 | ||
| 
 | ||
|         dependencies = [
 | ||
|             ('myapp', '0003_auto_20150129_1705'),
 | ||
|         ]
 | ||
| 
 | ||
|         operations = [
 | ||
|             migrations.AddField(
 | ||
|                 model_name='mymodel',
 | ||
|                 name='uuid',
 | ||
|                 field=models.UUIDField(max_length=32, unique=True, default=uuid.uuid4),
 | ||
|             ),
 | ||
|         ]
 | ||
| 
 | ||
|   You will need to make three changes:
 | ||
| 
 | ||
|   * 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`.
 | ||
| 
 | ||
|   * On the first operation (``AddField``), change ``unique=True`` to
 | ||
|     ``null=True`` -- this will create the intermediary null field.
 | ||
| 
 | ||
|   * Between the two operations, 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.
 | ||
| 
 | ||
|   The resulting migration should look similar to this::
 | ||
| 
 | ||
|     # -*- coding: utf-8 -*-
 | ||
|     from __future__ import unicode_literals
 | ||
| 
 | ||
|     from django.db import migrations, models
 | ||
|     import uuid
 | ||
| 
 | ||
|     def gen_uuid(apps, schema_editor):
 | ||
|         MyModel = apps.get_model('myapp', 'MyModel')
 | ||
|         for row in MyModel.objects.all():
 | ||
|             row.uuid = uuid.uuid4()
 | ||
|             row.save()
 | ||
| 
 | ||
|     class Migration(migrations.Migration):
 | ||
| 
 | ||
|         dependencies = [
 | ||
|             ('myapp', '0003_auto_20150129_1705'),
 | ||
|         ]
 | ||
| 
 | ||
|         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.
 | ||
| 
 | ||
|   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
 | ||
|   ``RunPython`` will have their original ``uuid``’s overwritten.
 |