Django использует миграции для переноса изменений в моделях (добавление поля, удаление модели и т.д.) на структуру базы данных. Миграции создавались в основном для автоматической работы, но вам необходимо знать когда их создавать, запускать и как решать различные проблемы.
Django предоставляет две команды для работы с миграциями и структурой базы данных:
migrate, которая отвечает за применение миграций, за откат миграций и за вывод статуса миграций.
makemigrations, которая отвечает за создание новых миграций на основе изменений в моделях.
sqlmigrate, которая выводит SQL запросы для миграции.
Следует рассматривать миграции, как систему контроля версий для базы данных. makemigrations отвечает за сохранение состояния моделей в файле миграции - аналог коммита - а migrate отвечает за их применение к базе данных.
Файлы с миграциями находятся в каталоге “migrations” приложения. Они являются частью приложения и должны распространятся вместе с остальным кодом приложения. Они должны создаваться при разработке и потом применятся на машинах коллег, тестовом и “боевом” серверах.
Примечание
Вы можете изменить пакет, который хранит миграции, указав его в настройке MIGRATION_MODULES.
Миграции работают идентично на одном и том же наборе данных. Это означает, что на сервере разработки, тестовом и “боевом” серверах вы получите один и тот же результат при одинаковых условиях выполнения миграций.
Django создаст миграции при любых изменениях модели или полей - даже тех параметров, которые не влияют на базу данных - т.к. единственный способ восстановить состояние моделей - это хранить все изменения в истории. Вам могут понадобится эти параметры в миграциях данных в будущем (например, если вы добавите собственную проверку данных).
Миграции поддерживаются всеми бэкендами, которые предоставляет Django, как и сторонними, если они реализуют API внесения изменений в структуру базы данных (через класс SchemaEditor).
Тем не менее, некоторые базы данных поддерживают больше возможностей, чем другие, в случаях когда речь идёт о миграциях схемы. Некоторые ограничения будут описаны далее.
PostgreSQL предоставляет больше всего возможностей для миграций структуры данных. Единственное ограничение в том, что добавление столбцов со значениями по умолчанию вызывает полную перезапись таблицы и требует времени, пропорциональное её размеру.
По этой причине рекомендуется всегда создавать новые столбцы с null=True, т.к. таким образом они будут добавлены сразу.
В MySQL отсутствует поддержка транзакций при изменении структуры. Это означает, что если миграция не выполнится из-за ошибки вам придется вручную откатывать изменения, чтобы попытаться снова (т.к. невозможно вернуться к исходному состоянию автоматически).
Кроме того, MySQL будет полностью переписывать таблицы почти для каждой операции изменения структуры, это занимает время, пропорциональное количеству строк в таблице. На медленном оборудовании это может занимать больше, чем минута на миллион строк. Добавление нескольких столбцов в таблицу с всего несколькими миллионами строк может заблокировать ваш сайт на более чем десять минут.
Наконец, MySQL имеет достаточно малый предел для длины имен столбцов, таблиц и индексов, а также ограничение на общий размер всех столбцов и индексов. Это означает, что индексы, которые могут создать другие бэкенды, не будут созданы MySQL.
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:
Apply all migrations: books
Running migrations:
Rendering model states... DONE
Applying books.0003_auto... OK
После того, как миграция отработала, добавьте миграции и изменения к моделям в одном коммите - таким образом, когда другие разработчики (или на “боевом” сервере) обновят код, они получат как изменения ваших моделей, так и миграции для них.
Вы можете указать свое название для миграции с помощью опции --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) было отличным обещанием, но не гарантией. Любое другое приложение, которое потребуется для удовлетворения зависимости, будет использовано автоматически.
Миграции сохраняются в так называемых “файлах миграции”. Это обычные 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.
Вы можете сериализировать менеджеры модели в миграции, чтобы использовать в их операциях 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()
Советуем ознакомиться с заметками в разделе “Исторические” модели.
“Начальные миграции” приложения – это миграции, которые создают первую версию таблиц для приложения. Обычно приложение содержит только одну начальную миграцию, но для сложной структуры моделей их может быть несколько.
Начальные миграции помечаются атрибутом initial = True в классе миграции. Если атрибут initial не указан, миграция будет считаться “начальной”, если это первая миграция в приложении (то есть она не зависит от другой миграции текущего приложения).
При запуске migrate с опцией --fake-initial начальные миграция выполняются по особенному. Если создаются таблицы (операция CreateModel), Django проверит наличие таблиц в базе данных, и пометит миграцию выполненной, если таблицы найдены. Аналогично при добавлении полей (операция AddField), Django проверит наличие полей. Без опции --fake-initial начальные миграции выполняются как и обычные.
Добавить миграции в новое приложение очень просто. Они уже настроены на использование миграций. Просто выполните makemigrations после изменений моделей.
Если ваше приложение уже содержит модели и таблицы в базе данных, но не содержит миграции (например, вы используете приложение для предыдущих версий Django), вам необходимо преобразовать, чтобы использовать миграции. Это просто:
$ python manage.py makemigrations your_app_label
В приложении будет создана начальная миграция. Теперь выполните python manage.py migrate --fake-initial, Django увидит начальную миграцию, и что таблицы, которые необходимо создать, уже существуют, и просто пометит миграцию как уже выполненную. (Без флага --fake-initial команда migrate вернет ошибку т.к. таблицы, которые она пытается создать, уже существуют.)
Обратите внимание, это работает только при соблюдении следующих условий:
Вы не меняли модели после создания таблиц в базе данных. Чтобы миграции сработали, необходимо сначала создать начальную миграцию, а потом вносить изменения, т.к. Django определяет изменения по файлам миграций, а не структуре в базе данных.
Вы не меняли самостоятельно структуру базы данных. Django не сможет определить, что структура базы данных не соответствует структуре ваших моделей. Скорее всего вы получите ошибку при выполнении миграций.
Был добавлен флаг --fake-initial для migrate. Ранее начальные миграции всегда автоматически помечались выполненными, если были найдены таблицы в базе данных.
При выполнении миграций Django использует сгенерированные версии ваших моделей, которые хранятся в файлах миграций. Если вы пишете Python код для выполнения миграции, используя операцию RunPython, или добавляете метод allow_migrate в ваш роутер базы данных, Django предоставит вам эти модели для использования.
Т.к. невозможно сериализовать произвольный код Python, эти версии моделей не будут содержать методы, который вы добавили в модели. Однако, модели будут содержать аналогичные поля, связи, менеджеры(только те, которые содержат use_in_migrations = True) и параметры Meta (с учетом версии модели, так что они могут отличаться от моделей, которые находятся на данный момент в приложении).
Предупреждение
Это означает, что вы НЕ сможете использовать переопределённый метод save(). Также НЕ будет использоваться переопределённый конструктор модели. Вы должны учитывать это при создании Python кода миграций!
Ссылки на функции, которые используются в параметрах поля (например, upload_to и limit_choices_to), и менеджеры моделей с use_in_migrations = True будут сериализированы в миграциях. Такие функции нельзя удалять из кода проекта, пока существуют миграции, которые ссылаются на них. Все собственные поля моделей также должы быть доступны т.к. они явно импортируются в миграциях.
В дополнение, родительские классы модели также сохраняются в миграциях в виде указателей. Их необходимо сохранять, пока существует миграция, которая ссылается на них. Но в качестве бонуса у вас будет доступ ко всем методам и менеджерам из родительских классов. Так что, если вам действительно необходим доступ в миграциях к собственным методам и менеджерам, вы можете вынести их в родительский класс.
Из предыдущего раздела вы узнали, что удаление собственных полей модели из проекта или используемых приложений может привести к проблемам с миграциями, если существуют миграции, которые ссылаются на эти поля.
Чтобы помочь решить эту проблему, были добавлены атрибуты в поля модели, которые могут указать на устаревшие поля при проверке проекта.
Добавьте атрибут 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 -*-
# Generated by Django A.B on YYYY-MM-DD HH:MM
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
]
Теперь необходимо создать новую функцию и указать её в RunPython. RunPython принимает в качестве аргумента функцию (или любой другой вызываемый объект), которая принимает два аргумента. Первый - это регистр приложений, который содержит приложения и исторические версии моделей, соответствующие текущей структуре, описанной в миграциях. Второй - SchemaEditor, который можно использовать для изменения структуры базы данных (но будьте осторожны, это может сбить с толку автоматическое определение изменений структуры моделей!)
Давайте создадим простую миграцию, которая заполняет новое поле name комбинацией значений first_name и last_name. Для этого будем использовать текущую версию модели и в цикле изменим все объекты:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
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):
initial = True
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 позволяет сериализовать следующее:
Объекты datetime.date, datetime.time и datetime.datetime (включая те, у которых указан часовой пояс)
Объекты decimal.Decimal
Объекты functools.partial, которые содержат сериализируемые значения func, args и keywords.
Объекты LazyObject, которые содержат сериализируемое значение.
Любое поле Django
Ссылку на любую функцию или метод (например datetime.datetime.today) (должны быть доступны на уровне модуля)
Ссылка на класс (должны быть доступны на уровне модуля)
Любой объект с методом deconstruct() (смотрите ниже)
Была добавлена возможность сериализации объектов functools.partial и LazyObject.
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), в тело модуля.
Вы можете научить 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, все строки, которые используются в ваших моделях и полях (например 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. В этом случае вы должны всегда выполнять makemigrations для самый старой версии Django, которую вы поддерживаете.
Система миграций поддерживает обратную совместимость как и остальная часть Django, и файлы миграций для Django X.Y должны работать для Django X.Y+1. Однако, система миграций не гарантирует обратную совместимость. Могут добавляться новые возможности и новые миграции не будут работать на старой версии Django.
Если вы уже используете South для миграций, то обновиться до django.db.migrations будет просто:
Убедитесь, что все установки проекта используют последнюю версию миграций
Удалите 'south' из INSTALLED_APPS.
Удалите все ваши файлы с миграциями (пронумерованные), но не удаляйте каталог и файл __init__.py. Не забудьте удалить файлы .pyc.
Выполните python manage.py makemigrations. Django увидит пустой каталог с миграциями и создаст новые начальные миграции в новом формате.
Выполните python manage.py migrate --fake-initial. Django увидит, что все таблицы в базе данных соответствуют начальным миграциям и пометит их как выполненные. (Django не проверяет соответствие структуры таблиц и моделей, только наличие таблицы в базе данных).
Был добавлен флаг --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 операций для изменений структуры базы данных, специальные операции, и создания своих операций.
Описывает как самостоятельно создать миграции для решения различных ситуаций.
Mar 31, 2016