Spec-Zone.ru › Django 1.8

Написание миграций базы данных

Этот документ объясняет, как структурировать и писать миграции базы данных для различных сценариев, с которыми вы можете столкнуться. Для вводной информации о миграциях см. руководство по теме.

Миграции данных и несколько баз данных

При использовании нескольких баз данных вам, возможно, придется определить, следует ли запускать миграцию на конкретной базе данных. Например, вы можете захотеть запустить миграцию только на определённой базе данных.

Для этого вы можете проверить псевдоним подключения к базе данных внутри операции RunPython , обратившись к атрибуту schema_editor.connection.alias.

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),
    ]

Вы также можете предоставить подсказки, которые будут переданы методу allow_migrate() маршрутизаторов баз данных в виде **hints:

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

Затем, чтобы использовать это в своих миграциях, сделайте следующее:

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'}),
    ]

Если ваша операция RunPython или RunSQL затрагивает только одну модель, рекомендуется передать model_name в качестве подсказки, чтобы сделать её работу как можно более прозрачной для маршрутизатора. Это особенно важно для многоразового использования и сторонних приложений.

Миграции, добавляющие уникальные поля

Применение «простой» миграции, добавляющей уникальное обязательное поле в таблицу с существующими строками, вызовет ошибку, так как значение, используемое для заполнения существующих строк, генерируется только один раз, что нарушает уникальное ограничение.

Поэтому необходимо выполнить следующие действия. В этом примере мы добавим обязательное UUIDField с заданным значением по умолчанию. Измените соответствующее поле в соответствии с вашими потребностями.

  • Добавьте поле в свою модель с помощью default=uuid.uuid4 и unique=True аргументов (выберите подходящее значение по умолчанию для типа поля, которое вы добавляете).
  • Запустите команду makemigrations. Это должно сгенерировать миграцию с операцией AddField.
  • Создайте два пустых файла миграций для того же приложения, дважды выполнив makemigrations myapp --empty. Мы переименовали файлы миграций, чтобы придать им осмысленные имена в примерах ниже.
  • Скопируйте операцию AddField из сгенерированной миграции (первый из трёх новых файлов) в последнюю миграцию и измените AddField на AlterField. Например:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.db import migrations, models
    import uuid
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0005_populate_uuid_values'),
        ]
    
        operations = [
            migrations.AlterField(
                model_name='mymodel',
                name='uuid',
                field=models.UUIDField(default=uuid.uuid4, unique=True),
            ),
        ]
    
  • Отредактируйте первый файл миграции. Сгенерированный класс миграции должен выглядеть примерно так:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0003_auto_20150129_1705'),
        ]
    
        operations = [
            migrations.AddField(
                model_name='mymodel',
                name='uuid',
                field=models.UUIDField(default=uuid.uuid4, unique=True),
            ),
        ]
    

    Измените unique=True на null=True — это создаст промежуточное поле с null и отложит создание уникального ограничения до тех пор, пока мы не заполним уникальные значения во всех строках.

  • В первом пустом файле миграции добавьте операцию RunPython или RunSQL для генерации уникального значения (UUID в примере) для каждой существующей строки. Например:

    # -*- 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', '0004_add_uuid_field'),
        ]
    
        operations = [
            # omit reverse_code=... if you don't want the migration to be reversible.
            migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
        ]
    
  • Теперь вы можете применить миграции как обычно с помощью команды migrate.

    Обратите внимание, что существует проблема гонки, если вы разрешаете создание объектов во время выполнения этой миграции. Объекты, созданные после AddField и до RunPython , будут иметь свои оригинальные uuid перезаписанные.

Управление порядком миграций

Django определяет порядок применения миграций не по имени файла каждой миграции, а путем построения графа, используя два свойства в классе Migration: dependencies и run_before.

Если вы использовали команду makemigrations, вы, вероятно, уже видели dependencies в действии, так как автоматически созданные миграции имеют это определено как часть процесса создания.

Свойство dependencies объявляется следующим образом:

from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0123_the_previous_migration'),
    ]

Обычно этого будет достаточно, но иногда вам может потребоваться гарантировать, что ваша миграция выполняется *до* других миграций. Это полезно, например, для того, чтобы миграции сторонних приложений выполнялись *после* вашего замещения AUTH_USER_MODEL.

Для этого поместите все миграции, которые должны зависеть от вашей, в атрибут run_before в вашем классе Migration:

class Migration(migrations.Migration):
    ...

    run_before = [
        ('third_party_app', '0001_do_awesome'),
    ]

По возможности используйте dependencies вместо run_before. Вы должны использовать run_before только в том случае, если указать dependencies в миграции, которую вы хотите выполнить после той, которую вы пишете, нежелательно или непрактично.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/howto/writing-migrations/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API