Подтвердить что ты не робот

Django migrations - рабочий процесс с несколькими ветвями dev

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

Моя проблема заключается в следующем: - у нас есть несколько ветвей функций в git, некоторые из них с миграциями django (некоторые из них изменяют поля или вообще удаляют их) - когда я переключаю ветки (с git checkout some_other_branch), база данных не всегда отражает новый код, поэтому я запускаю "случайные" ошибки, где столбец таблицы db больше не существует и т.д.

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

Есть ли хороший/чистый способ борьбы с этим прецедентом? Я думаю, что post-checkout git hook script может выполнить необходимые миграции, но я даже не знаю, возможны ли откат возврата.

4b9b3361

Ответ 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, вы повторно применяете свое предыдущее состояние базы данных просмотрев файл дампа.

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

Обработка конфликтов миграции при их возникновении кажется мне более легкой.

Ответ 2

У меня нет хорошего решения, но я чувствую боль.

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

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

Я представляю оболочку для git -checkout, которая:

  • Заметьте новейшую миграцию для каждого из ваших INSTALLED_APPS
  • Входит в запрошенную ветку и отмечает самые новые миграции там
  • Для каждого приложения, где миграции в # 1 находятся дальше, чем в # 2, вернитесь к самой высокой миграции в # 2
  • Проверьте новую ветку
  • Для каждого приложения, где миграции в # 2 были впереди # 1, переместите вперед

Простой вопрос программирования!

Ответ 3

Я знаю, что это старый вопрос, но в Findster мы столкнулись с той же битвой, что и мы, чтобы перейти к конвейеру автоматической миграции БД.

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

Мы развиваемся в подходе GithubFlow. Наша проблема здесь заключается в управлении зависимостями между миграциями, так как DEV-A и DEV-B создают ветку из master в одной точке, и если каждая из них создает новые миграции, все 2 ветки будут иметь файлы миграции с одинаковой зависимостью. Я ищу решение.

БР :)

Эдуардо