Миграции

Добавлено в Django 1.7.

Django использует миграции для переноса изменений в моделях (добавление поля, удаление модели и т.д.) на структуру базы данных. Миграции создавались в основном для автоматической работы, но вам необходимо знать когда их создавать, запускать и как решать различные проблемы.

Краткая история

До версии 1.7, Django позволял только добавлять новые модели в базу данных; не было возможности изменять или удалять существующие модели, используя команду syncdb (предок команды migrate).

Сторонние инструменты, самый известный South, позволяли создавать и выполнять миграции. Со временем было решено перенести этот функционал в Django.

Команды

Django предоставляет две команды для работы с миграциями и структурой базы данных:

  • migrate, которая отвечает за применение миграций, за откат миграций и за вывод статуса миграций.

  • makemigrations, которая отвечает за создание новых миграций на основе изменений в моделях.

  • sqlmigrate, которая выводит SQL запросы для миграции.

Стоит отметить, что миграции создаются и работают в контексте отдельного приложения. В частности, можно создать приложение, которое не использует миграции - такие приложения имитируют старое поведение и просто создают новые модели.

Следует рассматривать миграции, как систему контроля версий для базы данных. makemigrations отвечает за сохранение состояния моделей в файле миграции - аналог коммита - а migrate отвечает за их применение к базе данных.

Файлы с миграциями находятся в каталоге “migrations” приложения. Они являются частью приложения и должны распространятся вместе с остальным кодом приложения. Они должны создаваться при разработке и потом применятся на машинах коллег, тестовом и “боевом” серверах.

Примечание

Вы можете изменить пакет, который хранит миграции, указав его в настройке MIGRATION_MODULES.

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

Django создаст миграции при любых изменениях модели или полей - даже тех параметров, которые не влияют на базу данных - т.к. единственный способ восстановить состояние моделей - это хранить все изменения в истории. Вам могут понадобится эти параметры в миграциях данных в будущем (например, если вы добавите собственную проверку данных).

Поддержка бэкендами

Миграции поддерживаются всеми бэкендами, которые предоставляет Django, как и сторонними, если они реализуют API внесения изменений в структуру базы данных (через класс SchemaEditor).

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

PostgreSQL

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

По этой причине рекомендуется всегда создавать новые столбцы с null=True, т.к. таким образом они будут добавлены сразу.

MySQL

В MySQL отсутствует поддержка транзакций при изменении структуры. Это означает, что если миграция не выполнится из-за ошибки вам придется вручную откатывать изменения, чтобы попытаться снова (т.к. невозможно вернуться к исходному состоянию автоматически).

Кроме того, MySQL будет полностью переписывать таблицы почти для каждой операции изменения структуры, это занимает время, пропорциональное количеству строк в таблице. На медленном оборудовании это может занимать больше, чем минута на миллион строк. Добавление нескольких столбцов в таблицу с всего несколькими миллионами строк может заблокировать ваш сайт на более чем десять минут.

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

SQLite

SQLite очень плохо поддерживает изменения в структуре базы данных, но Django пытается эмулировать их следующим образом:

  • Создание новой таблицы для новой структуры

  • Копирование данных в новую таблицу

  • Удаление старой таблицы

  • Переименование новой таблицы

Этот процесс как правило хорошо работает, но может быть медленным и иногда глючит. Не рекомендуется использовать и мигрировать SQLite на “боевом” сервере, если вы не очень осведомлены о рисках и его ограничениях. Django поддерживает SQLite, чтобы позволить разработчикам использовать SQLite для разработки простых проектов.

Работа с миграциями

Работать с миграциями просто. Измените модели - например, добавьте поле и удалите модель - и затем запустите makemigrations:

$ python manage.py makemigrations
Migrations for 'books':
  0003_auto.py:
    - Alter field author on book

Ваши модели будут просканированы и сравнены с версией, которая содержится в файлах миграций, затем будут созданы новые миграции. Не забывайте проверять вывод команды, чтобы понимать, как makemigrations видит ваши изменения - для сложных изменений вы можете получить не совсем ожидаемый результат.

Создав новые миграции, вам следует применить их к вашей базе данных, чтобы убедиться, что всё работает:

$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: sessions, admin, messages, auth, staticfiles, contenttypes
  Apply all migrations: books
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Installed 0 object(s) from 0 fixture(s)
Running migrations:
  Applying books.0003_auto... OK

Команда работает в два этапа. Сначала она синхронизирует приложения без миграций (по сути выполняет действия аналогичные syncdb), а затем применяются миграции, которые ещё не применялись к базе данных.

После того, как миграция отработала, добавьте миграции и изменения к моделям в одном коммите - таким образом, когда другие разработчики (или на “боевом” сервере) обновят код, они получат как изменения ваших моделей, так и миграции для них.

Добавлено в Django 1.8.

Вы можете указать свое название для миграции с помощью опции --name:

$ python manage.py makemigrations --name changed_my_model your_app_label

Контроль версий

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

Не волнуйтесь - номер просто для разработчиков, Django главное, чтобы миграции имели уникальные названия. Миграции определяют зависимости к другим миграции - включая предыдущую миграцию из этого приложения. Таким образом можно определить наличие двух миграций с неправильным порядком.

Когда это произойдет, Django предложит выбрать один из вариантов действий. Если Django определит, что достаточно безопасно может сам решить проблему, он предложит автоматически поменять порядок конфликтующим миграциям. Если нет, то вам придется самостоятельно это сделать - не волнуйтесь, это не трудно, и описано в Файлы с миграциями ниже.

Зависимости

В то время как миграция находятся в контексте одного приложения, таблицы и зависимости, определенные вашими моделями, обычно намного сложнее, и могут работать не только с одним приложением. Когда вы делаете миграцию, которая требует что-то ещё для запуска - например, вы добавляете ForeignKey в вашем books приложении на приложение authors - в результате миграция будет содержать зависимость от миграции в authors.

Это означает, что при запуске миграций, сначала применяются миграции приложения authors, создаётся таблица, на которую ссылается ForeignKey, и затем миграция, которая создаёт ForeignKey. Иначе миграция попыталась бы создать ForeignKey на таблицу, которая может ещё не существовать, и мы получили бы ошибку.

Такое поведение зависимостей влияет на большинство миграционных операций, которые вы ограничили рамками одного приложения. Подобное ограничение (в makemigrations или migrate) было отличным обещанием, но не гарантией. Любое другое приложение, которое потребуется для удовлетворения зависимости, будет использовано автоматически.

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

Предупреждение

Даже если ваш проект работает с приложением без миграций, которое ссылается на приложение с миграциями, Django не сможет создать все необходимые проверки(constraints) для внешних ключей!

Вы столкнетесь с этим при использовании заменяемых моделей (например, AUTH_USER_MODEL). Все приложения, которые работают с такими моделями, должны содержать миграции. Вам может не повезти и какое-то стороннее приложение, которое использует вашу заменяемую модель, будет без миграций. С течением времени всё больше и больше сторонних приложений будут поддерживать миграции, но вы можете и сами их создать (указав в MIGRATION_MODULES где искать миграции), или же не использовать миграции в своем приложении, которое определяет заменяемую модель.

Файлы с миграциями

Миграции сохраняются в так называемых “файлах миграции”. Это обычные Python файлы с классом миграции, который соблюдает определенный интерфейс. В нём декларативно можно описать все необходимые операции и прочее.

Базовый файл миграции выглядит следующим образом:

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [("migrations", "0001_initial")]

    operations = [
        migrations.DeleteModel("Tribble"),
        migrations.AddField("Author", "rating", models.IntegerField(default=0)),
    ]

При загрузке файла миграции (импортируя как Python модуль) Django ищет дочерний класс django.db.migrations.Migration, который должен называться Migration. Затем он анализирует четыре атрибута класса, из которых обычно используются только два:

  • dependencies - список зависимых миграций.

  • operations - список подклассов Operation, которые определяют необходимые для миграции операции.

Список операций - самое главное в миграции. Он декларативно описывает необходимые операции для изменения структуры базы данных. Django анализирует все операции и в памяти строит схему всех необходимых изменений, чтобы сгенерировать необходимые SQL-запросы.

Схема в памяти также используется чтобы определить отличия между вашими текущими моделями и состоянием моделей, описанном в миграциях. Django проходит по всем изменениям и создает структуру моделей на момент последнего выполнения makemigrations. Затем эта структура сравнивается со структурой моделей в models.py и определяются изменения, которые вы внесли в ваши модели.

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

Собственные поля

Вы не можете поменять количество позиционных аргументов в уже промигрированном собственном поле, в таком случае будет вызвано исключение TypeError. Это вызвано тем, что старая миграция попытается вызвать измененный метод __init__ со старыми аргументами. Поэтому, если вам необходимо добавить новый аргумент в конструктор поля, используйте именованный аргумент и добавьте в конструктор что-то вроде assert 'argument_name' in kwargs.

Менеджеры модели

Добавлено в Django 1.8.

Вы можете сериализировать менеджеры модели в миграции, чтобы использовать в их операциях RunPython. Для этого укажите атрибут use_in_migrations в классе менеджера:

class MyManager(models.Manager):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

Если вы используете функцию :meth:`~django.db.models.from_queryset`для создания менеджера, вам следует унаследоваться от сгенерированного класса:

class MyManager(MyBaseManager.from_queryset(CustomQuerySet)):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

Советуем ознакомиться с заметками в разделе “Исторические” модели.

Добавление миграций в приложение

Добавить миграции в новое приложение очень просто. Они уже настроены на использование миграций. Просто выполните makemigrations после изменений моделей.

Если ваше приложение уже содержит модели и таблицы в базе данных, но не содержит миграции (например, вы используете приложение для предыдущих версий Django), вам необходимо преобразовать, чтобы использовать миграции. Это просто:

$ python manage.py makemigrations your_app_label

В приложении будет создана начальная миграция. Теперь выполните python manage.py migrate --fake-initial, Django увидит начальную миграцию, и что таблицы, которые необходимо создать, уже существуют, и просто пометит миграцию как уже выполненную. (Без флага --fake-initial команда migrate вернет ошибку т.к. таблицы, которые она пытается создать, уже существуют.)

Обратите внимание, это работает только при соблюдении следующих условий:

  • Вы не меняли модели после создания таблиц в базе данных. Чтобы миграции сработали, необходимо сначала создать начальную миграцию, а потом вносить изменения, т.к. Django определяет изменения по файлам миграций, а не структуре в базе данных.

  • Вы не меняли самостоятельно структуру базы данных. Django не сможет определить, что структура базы данных не соответствует структуре ваших моделей. Скорее всего вы получите ошибку при выполнении миграций.

“Исторические” модели

При выполнении миграций Django использует сгенерированные версии ваших моделей, которые хранятся в файлах миграций. Если вы пишете Python код для выполнения миграции, используя операцию RunPython, или добавляете метод allow_migrate в ваш роутер базы данных, Django предоставит вам эти модели для использования.

Т.к. невозможно сериализовать произвольный код Python, эти версии моделей не будут содержать методы, который вы добавили в модели. Однако, модели будут содержать аналогичные поля, связи, менеджеры(только те, которые содержат use_in_migrations = True) и параметры Meta (с учетом версии модели, так что они могут отличаться от моделей, которые находятся на данный момент в приложении).

Предупреждение

Это означает, что вы НЕ сможете использовать переопределённый метод save(). Также НЕ будет использоваться переопределённый конструктор модели. Вы должны учитывать это при создании Python кода миграций!

Ссылки на функции, которые используются в параметрах поля (например, upload_to и limit_choices_to), и менеджеры моделей с use_in_migrations = True будут сериализированы в миграциях. Такие функции нельзя удалять из кода проекта, пока существуют миграции, которые ссылаются на них. Все собственные поля моделей также должы быть доступны т.к. они явно импортируются в миграциях.

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

Советы по удалению полей модели

Добавлено в Django 1.8.

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

Чтобы помочь решить эту проблему, были добавлены атрибуты в поля модели, которые могут указать на устаревшие поля при проверке проекта.

Добавьте атрибут system_check_deprecated_details к полю модели:

class IPAddressField(Field):
    system_check_deprecated_details = {
        'msg': (
            'IPAddressField has been deprecated. Support for it (except '
            'in historical migrations) will be removed in Django 1.9.'
        ),
        'hint': 'Use GenericIPAddressField instead.',  # optional
        'id': 'fields.W900',  # pick a unique ID for your field.
    }

После определенного периода поддержки устаревшего кода (Django использует два мажорных релиза для своих полей), замените system_check_deprecated_details на system_check_removed_details со следующим значением:

class IPAddressField(Field):
    system_check_removed_details = {
        'msg': (
            'IPAddressField has been removed except for support in '
            'historical migrations.'
        ),
        'hint': 'Use GenericIPAddressField instead.',
        'id': 'fields.E900',  # pick a unique ID for your field.
    }

Вы должны сохранить методы поля поля, которые используются в миграции: __init__(), deconstruct() и get_internal_type(). Храните это поле-заглушку, пока существуют миграции, которые ссылаются на него. Например, после объединения миграций и удаления старых, вы сможете полностью удалить эти поля.

Миграция данных

Вы можете использовать миграции не только для изменения структуры базы данных, но и для изменения данных. Можно и в контексте изменения структуры, чтобы мигрировать данные на новую структуру таблицы.

Миграции, которые изменяют данные, обычно называют “миграциями данных”. Их лучше выносить в отдельную миграцию.

Django не может автоматически создать миграции данных для вас, как это происходит с миграциями структуры, но их не сложно создать самостоятельно. Файлы миграций в Django содержат Операции. Для миграций данных вы будете использовать в основном RunPython.

Для начала создайте пустую миграцию (Django создаст файл миграции, положит его в правильно место, создаст название и добавит необходимые зависимости):

python manage.py makemigrations --empty yourappname

Теперь откройте файл, он будет выглядеть следующим образом:

# -*- coding: utf-8 -*-
from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
    ]

Теперь необходимо создать новую функцию и указать её в RunPython. RunPython принимает в качестве аргумента функцию (или любой другой вызываемый объект), которая принимает два аргумента. Первый - это регистр приложений, который содержит приложения и исторические версии моделей, соответствующие текущей структуре, описанной в миграциях. Второй - SchemaEditor, который можно использовать для изменения структуры базы данных (но будьте осторожны, это может сбить с толку автоматическое определение изменений структуры моделей!)

Давайте создадим простую миграцию, которая заполняет новое поле name комбинацией значений first_name и last_name. Для этого будем использовать текущую версию модели и в цикле изменим все объекты:

# -*- coding: utf-8 -*-
from django.db import models, migrations

def combine_names(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Person = apps.get_model("yourappname", "Person")
    for person in Person.objects.all():
        person.name = "%s %s" % (person.first_name, person.last_name)
        person.save()

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(combine_names),
    ]

Теперь выполним python manage.py migrate и миграция данных будет применена вместе с остальными миграциями.

Вы можете передать вторым аргументом RunPython еще одну функцию, которая будет использоваться при отмене миграции. Если такая функция не указана, то при попытке отменить миграцию будет вызвано исключение.

Доступ к моделям в других приложениях

Если функция для RunPython использует модели другого приложения, атрибут dependencies миграции должен включать последнюю миграцию приложения, модель которого используется. Иначе вы можете получить исключение: LookupError: No installed app with label 'myappname' в функции RunPython при использовании apps.get_model().

В примере у нас есть миграция из приложения app1, которая используем модели из приложения app2. Нас не интересует реализация move_m1, но мы знаем, что этой функции необходим доступ к моделям из обоих приложений. Для этого мы добавили в зависимости последнюю миграцию app2:

class Migration(migrations.Migration):

    dependencies = [
        ('app1', '0001_initial'),
        # added dependency to enable using models from app2 in move_m1
        ('app2', '0004_foobar'),
    ]

    operations = [
        migrations.RunPython(move_m1),
    ]

Миграции для продвинутых

Если вы хотите узнать как писать более сложные миграции, или как создавать миграции с нуля, смотрите раздел об операциях в миграциях и “how-to” о создании миграций.

Объединение миграций

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

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

Django загрузит все ваши миграции, соберёт последовательность объектов Operation, затем попытается оптимизировать и сократить этот список. Например, Django понимает, что CreateModel и DeleteModel отменяют друг друга, и что AddField может быть добавлена в CreateModel.

Когда список операций будет оптимизирован насколько возможно - это зависит от сложности связей между моделями, использовались ли операции RunSQL или RunPython (которые нельзя оптимизировать) - Django добавит их в новые миграции.

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

Это позволяет объединить миграции и не сломать проект на сервере, который ещё не обновили до последней версии. Рекомендуем следующую последовательность действий: объединяем миграции, старые не удаляем, коммитим и обновляем все сервера при следующем релизе (если это распространяемое приложение, убеждаемся, что все пользователи обновились до последней версии), удаляем старые миграции, коммитим и обновляем сервера до последней релизной версии.

Для объединения миграций существует команда djadmin:squashmigrations. Просто передайте ей название приложения и название миграции, до который вы хотите выполнить объединение:

$ ./manage.py squashmigrations myapp 0004
Will squash the following migrations:
 - 0001_initial
 - 0002_some_change
 - 0003_another_change
 - 0004_undo_something
Do you wish to proceed? [yN] y
Optimizing...
  Optimized from 12 operations to 7 operations.
Created new squashed migration /home/andrew/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_somthing.py
  You should commit this migration but leave the old ones in place;
  the new migration will be used for new installs. Once you are sure
  all instances of the codebase have applied the migrations you squashed,
  you can delete them.

Обратите внимание, зависимости между моделями могут быть очень сложными. В результате объединения может получиться неработающая миграция или неправильно оптимизированная (в этом случае можете попробовать с опцией --no-optimize, и желательно сообщить нам о проблеме), или может вызывать исключение CircularDependencyError (в этом случае вы можете самостоятельно исправить проблему).

Чтобы устранить исключение CircularDependencyError, вынесите один из ForeignKey, который привел к циклической зависимости, в отдельную миграцию и перенести зависимость миграции в другое приложение, которое использует этот ForeignKey. Если вы не уверены как сделать это правильно, посмотрите как makemigrations делает это при создании новой миграции по вашим моделям. В следующих версиях Django мы обновим squashmigrations, чтобы такие проблемы решались автоматически.

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

После этого объединенную миграцию можно преобразовать в обычную начальную миграцию:

  • Удалите все миграции, которые она заменяет

  • Удалите аргумент replaces в классе Migration объединенной миграции (он указывает Django, что это объединенная миграция)

Примечание

Объединив миграции в новую, вы не можете снова использовать её при новом объединении, пока она не будет преобразована в обычную миграцию.

Сериализация значений

Миграции - это Python файлы, которые содержат старые определения ваших моделей. Поэтому, чтобы создать их, Django необходимо получить текущее состояние ваших моделей и сериализовать его в файле.

Хотя Django может сериализовать большинство вещей, есть некоторые веши, которые нельзя сериализовать в представление Python - нет в Python стандарта, который определяет как преобразовать значение обратно в код (repr() работает только для простых значений и не позволяет указать путь для импорта).

Django позволяет сериализовать следующее:

  • int, long, float, bool, str, unicode, bytes, None
  • list, set, tuple, dict
  • Объекты datetime.date, datetime.time и datetime.datetime (включая те, у которых указан часовой пояс)

  • Объекты decimal.Decimal

  • Любое поле Django

  • Ссылку на любую функцию или метод (например datetime.datetime.today) (должны быть доступны на уровне модуля)

  • Ссылка на класс (должны быть доступны на уровне модуля)

  • Любой объект с методом deconstruct() (смотрите ниже)

Изменено в Django 1.7.1:

Была добавлена возможность сериализовать datetime с часовым поясом.

Django может сериализовать следующее только в Python 3:

  • Непривязанные методы в теле класса (смотрите ниже)

Django не может сериализовать:

  • Вложенные классы

  • Экземпляры произвольного класса (например MyClass(4.3, 5.7))

  • Лямбда-функции

Т.к. __qualname__ был добавлен только в Python 3, Django может сериализовать следующее только в Python 3 (непривязанный метод в теле класса), но не может в Python 2:

class MyModel(models.Model):

    def upload_to(self):
        return "something dynamic"

    my_file = models.FileField(upload_to=upload_to)

Для Python 2 мы рекомендуем вынести методы, которые используются как значения для upload_to или других подобных параметров, принимающих функции (например default), в тело модуля.

Метод deconstruct()

Вы можете научить Django сериализовать объекты вашего класса, добавив ему метод deconstruct(). Он не принимает аргументы и должен вернуть кортеж из трех элементов (path, args, kwargs):

  • path - Python путь для импорта класса, включая название класса (например myapp.custom_things.MyClass). Если класс не доступен для импорта напрямую из модуля, его нельзя сериализировать.

  • args - список позиционных аргументов, которые необходимо передать в метод __init__. Аргументы также должны быть сериализируемыми.

  • kwargs - список именованных аргументов, которые необходимо передать в метод __init__. Аргументы также должны быть сериализируемыми.

Примечание

Метод deconstruct() собственных полей немного отличается, он должен возвращать кортеж из четырех элементов.

Django запишет полученное значение, как инициализацию для всего класса с заданными аргументами, аналогично тому, как это делается для встроенных полей.

Чтобы Django не создавал новую миграцию при каждом выполнении makemigrations, добавьте метод __eq__() к декорируемому классу. Эта функция будет вызываться Django, чтобы определить не поменялось ли состояние моделей.

Если все аргументы вашего класса сериализируемые, то для автоматического создания метода вы можете использовать декоратор класса @deconstructible из django.utils.deconstruct, чтобы добавить метод deconstruct():

from django.utils.deconstruct import deconstructible

@deconstructible
class MyCustomClass(object):

    def __init__(self, foo=1):
        self.foo = foo
        ...

    def __eq__(self, other):
        return self.foo == other.foo

Декоратор сохраняет все аргументы, передаваемые в конструктор, и возвращает их при вызове deconstruct().

Поддержка Python 2 и 3

Чтобы создать миграции, которые поддерживают Python 2 и 3, все строки, которые используются в ваших моделях и полях (например verbose_name, related_name, и т.д.), должны быть байтовыми строками или текстовыми (unicode) и в Python 2, и Python 3 (а не байтами в Python 2 и текстом в Python 3, что бывает по умолчанию, если тип строки явно не указан.) Иначе выполнение makemigrations на Python 3 создаст миграцию, которая преобразует все строковые атрибуты в текст.

Самый простой способ добиться этого - следовать гайду Django по переходу на Python 3 и убедиться, что все модули содержат в начале from __future__ import unicode_literals, и все строки в них являются юникод-строками, независимо от версии Python. Если вы добавите это текущий проект, который содержим миграции, созданные на Python 2, при следующем запуске makemigrations на Python 3 будет создана большая миграция с преобразованием всех байтовых строк в текстовые. Это нормально и необходимо выполнить всего лишь раз.

Поддержка нескольких версий Django

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

Система миграций поддерживает обратную совместимость как и остальная часть Django, и файлы миграций для Django X.Y должны работать для Django X.Y+1. Однако, система миграций не гарантирует обратную совместимость. Могут добавляться новые возможности и новые миграции не будут работать на старой версии Django.

Обновление с South

Если вы уже используете South для миграций, то обновиться до django.db.migrations будет просто:

  • Убедитесь, что все установки проекта используют последнюю версию миграций

  • Удалите 'south' из INSTALLED_APPS.

  • Удалите все ваши файлы с миграциями (пронумерованные), но не удаляйте каталог и файл __init__.py. Не забудьте удалить файлы .pyc.

  • Выполните python manage.py makemigrations. Django увидит пустой каталог с миграциями и создаст новые начальные миграции в новом формате.

  • Выполните python manage.py migrate --fake-initial. Django увидит, что все таблицы в базе данных соответствуют начальным миграциям и пометит их как выполненные. (Django не проверяет соответствие структуры таблиц и моделей, только наличие таблицы в базе данных).

Это всё! Единственной проблемой могут стать циклические внешние ключи. В этом случае makemigrations может создать несколько начальных миграций и вам необходимо самостоятельно пометить их как выполненные:

python manage.py migrate --fake yourappnamehere
Изменено в Django 1.8:

Был добавлен флаг --fake-initial для migrate. Ранее начальные миграции всегда автоматически помечались выполненными, если были найдены таблицы в базе данных.

Сторонние библиотеки и приложения

Если вы разрабатываете библиотеку или приложение и хотите поддерживать как миграции South (для Django 1.6 и ниже) так и Django (для 1.7 и выше), вам необходимо предоставлять параллельно два набора миграций в вашем приложении.

Для этого South 1.0 сначала будет искать South-миграции в каталоге south_migrations, а затем в migrations. Проект пользователя будет использовать правильный набор миграций пока South миграции находятся в каталоге south_migrations, а миграции Django в каталоге migrations.

Подробности смотрите в списке обновлений South 1.0.

См.также

Описание операций миграции

Описывает API операций для изменений структуры базы данных, специальные операции, и создания своих операций.

“how-to” о создании миграций

Описывает как самостоятельно создать миграции для решения различных ситуаций.