Ответ 1
Откат миграции возможен и обычно выполняется с помощью django.
Учитывая следующую модель:
class MyModel(models.Model):
pass
Если вы запустите python manage.py makemigrations myapp
, он будет генерировать начальную миграцию script.
Затем вы можете запустить python manage.py migrate myapp 0001
, чтобы применить эту начальную миграцию.
Если после этого вы добавите поле в свою модель:
class MyModel(models.Model):
my_field = models.CharField()
Затем восстановите новую миграцию и примените ее, вы можете вернуться к исходному состоянию. Просто беги
python manage.py migrate myapp 0001
, и ORM вернется назад, удалив новое поле.
Это сложнее, когда вы занимаетесь миграцией данных, потому что вам нужно написать код вперед и назад.
Учитывая пустую миграцию, созданную с помощью python manage.py makemigrations myapp --empty
,
вы получите что-то вроде:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
def forward(apps, schema_editor):
# load some data
MyModel = apps.get_model('myapp', 'MyModel')
while condition:
instance = MyModel()
instance.save()
def backward(apps, schema_editor):
# delete previously loaded data
MyModel = apps.get_model('myapp', 'MyModel')
while condition:
instance = MyModel.objects.get(myargs)
instance.delete()
class Migration(migrations.Migration):
dependencies = [
('myapp', '0003_auto_20150918_1153'),
]
operations = [
migrations.RunPython(forward, backward),
]
Для чистых миграций загрузки данных вам обычно не требуется обратная миграция.
Но когда вы изменяете схему и обновляете существующие строки,
(например, преобразование всех значений в столбце в slug), вам обычно приходится писать обратный шаг.
В нашей команде мы стараемся избегать одновременного использования одних и тех же моделей, чтобы избежать столкновения.
Если это невозможно, и создаются две миграции с таким же числом (например, 0002)
вы все равно можете переименовать один из них, чтобы изменить порядок, в котором они будут применяться (также не забудьте обновить
атрибут dependencies
в классе миграции в новый порядок).
Если вы в конечном итоге работаете над одними и теми же полями модели в разных функциях, вы все равно будете в беде, но это может означать, что эти функции связаны и должны быть обработаны вместе в одной ветки.
Для части git -hooks, возможно, можно что-то написать, предположив, что вы находитесь на ветке mybranch
и хотите проверить еще одну ветвь функции myfeature
:
- Перед переключением вы сбрасываете список применяемых в настоящее время миграций
временный файл
mybranch_database_state.txt
- Затем вы применяете миграцию ветвей
myfeature
, если есть - Затем, при проверке
mybranch
, вы повторно применяете свое предыдущее состояние базы данных просмотрев файл дампа.
Однако для меня это кажется немного хакерским, и, вероятно, будет очень сложно правильно обрабатывать все сценарии: переустановка, слияние, сборка вишни и т.д.
Обработка конфликтов миграции при их возникновении кажется мне более легкой.