Как удалить все миграции django
Перейти к содержимому

Как удалить все миграции django

  • автор:

Django — Урок 046. Сброс миграций в проекте

В процессе разработки проекта на Django мы можем столкнуться с неприятной ситуацией, когда некоторые пакеты и модули были удалены и, соответственно, модели из этих пакетов больше не использовались. Но в то же время сквош миграций приложений не позволяет удалить эти пакеты, так как миграции имеют много циклических зависимостей. В результате удаление ненужных пакетов становится довольно сложной задачей. Так как разрешение таких зависимостей становится нетривиальной задачей. Для меня таким неприятным пакетом был Django CKEditor, который присутствовал почти везде. В итоге этот пакет из-за миграций довольно долго оставался в списке requirements.txt, хотя по факту на сайте вообще не использовался. Чтобы избавиться от таких зависимостей миграций, нужно удалить все миграции, при этом не удаляя контент, который был создан этими миграциями. А затем создать новую начальную миграцию и применить ее к базе данных также без внесения новых изменений в структуру базы данных.

Как это сделать?

  1. Вернуть все миграции в нулевое состояние с параметром fake. Это означает, что информация о миграции будет удалена, но содержимое не изменится.
python manage.py migrate app zero --fake
git rm "app/migrations/*"
python manage.py makemigrations app
python manage.py migrate app --fake

Вывод

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

При этом на тестовом сервере можно создать новую миграцию и добавить ее в репозиторий git.

Затем на рабочем сервере вам нужно будет сделать следующее.

python manage.py migrate app zero --fake git pull python manage.py migrate app --fake

Рекомендуем хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB

Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Рекомендуемые статьи по этой тематике

По статье задано0 вопрос(ов)

Подписка на обсуждение 1
Подписка на раздел 176

Вам это нравится? Поделитесь в социальных сетях!

Как удалить миграцию?

Случайно сделал неудачную миграцию и теперь не знаю как ее удалить. 🙁 Т.е. как бы миграция еще не прошла, я только сделал makemigrations. Оно миграцию создало, но при вызове migrate выкинуло ошибку (полю даты случайно пустую строку по умолчанию задал). Я ее исправил и сделал снова makemigrations и migrate, но оно теперь продолжает на команде migrate ругаться на ту ошибку. Как откатить ту миграцию?

  • Вопрос задан более трёх лет назад
  • 2763 просмотра

8 комментариев

Оценить 8 комментариев

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

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

Інтенсивний курс від laba: Product management.
Від ідеї до успішного продукту.

Меня зовут Михаил Сердюк, я Backend Developer в NIX и спикер IT-конференции NIX MultiConf . В этой статье я расскажу, как решить проблемы, которые могут возникнуть во время миграций в Django. Погнали!

Что такое миграции

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

Професійний курс від mate.academy: Python Вечірній.
Поглиблене вивчення Python.

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

Например, в Question нужно добавить поле для описания title вопроса. Может показаться, что достаточно просто вписать его, но на самом деле этого мало. Чтобы Django воспринял эти изменения и занес их в базу данных, модель нужно промигрировать в Django. В следующем примере я намеренно задал для поля title параметр blank=True . Чуть дальше по тексту объясню это:

Итак, мы изменили базу данных. Теперь нужно создать миграцию. Для этого прописываем команду manage.py makemigrations . После этого Django автоматически создаст файл с миграциями. Эти файлы создаются в хронологическом порядке, по нумерации. Когда мы первый раз запускаем приложение, появляется initial-миграция, а после нее — следующие. В нашем случае это вторая миграция с прописанными в модели переменами.

Но у нас появились только файлы, сравнившие состояние файла с моделями приложения. Для этого Django проанализировал файлы миграции, созданные ранее, с классами и моделями в файле model.py. Разница между ними и стала основой файла миграции. Но для использования этого файла в базе данных необходимо запустить еще одну команду — manage.py migrate .

Високорівневий курс від laba: Фінансовий аналіз.
Оцінюйте фінансову стабільність та перспективи.

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

Давайте разоберемся, что представляет собой сам файл с миграцией :

  • Во-первых, в нем указываются зависимости, из которых он создан. Для этого делается ссылка из базы данных на последнюю примененную миграцию.
  • Во-вторых, в файле указываются требуемые изменения в базе данных. В нашем случае это создание в модели question нового поля с названием title и параметры для него:

Зачем разбираться с миграциями

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

Объясню по аналогии. Клиенту требуется транспорт, на котором он сможет добраться из пункта А до пункта Б и перевезти груз. Исполнитель, как рациональный человек, пойдет по пути наименьшего сопротивления и сделает велосипед:

    Это транспорт? Да.

Професійний курс від skvot: PR basis.
Засвоєте основи PR та комунікації.

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

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

Если вернуться к нашей аналогии, ситуация выглядела примерно так:

  • во-первых, расстояние от пункта А до пункта Б большое, поэтому требуется транспорт намного быстрее велосипеда;
  • во-вторых, по пути немало подъемов и спусков, поэтому вместо педалей лучше установить двигатель;
  • в-третьих, использование транспорта планируется в течение года, поэтому необходима кабина с обогревателем и кондиционером;
  • да и вообще грузы большие, и багажника на велосипеде маловато.

После замечаний разработчик вносит изменения в структуру базы данных и впоследствии проект трансформируется. Результаты изменений можно увидеть на иллюстрации ниже. Кстати, эта схема еще не конечный вариант, а где-то 10% от реальной структуры:

Этот пример говорит нам: постоянные изменения базы данных — это нормально. Ибо просчитать сходу возможные риски достаточно сложно. Задача может корректироваться несколько раз. Да, откровенно говоря, иногда сам заказчик не может четко описать нужный ему продукт.

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

Такое может произойти в нескольких случаях. К счастью, есть действенные варианты, как с этим справиться.

Как заменить миграцию

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

Несколько более сложная ситуация — когда мы и запускали команду migrate и применили изменения с миграциями в базу данных. Для решения такой проблемы нужно понять, важна ли база данных. Если ею можно пренебречь, удаляйте все миграции и базу данных, создавайте новые миграции с необходимыми изменениями и мигрируйте в новую БД. Но если база данных важна, тогда произведите откат к предыдущим миграциям. Для этого вводим команду manage.py show migration .

Далее увидим применяемые в базе данных миграции. В моем случае предыдущей была 0010_previous_migration . Чтобы к ней откатиться, мы прописываем команду:

manage.py migrate my_app 0010_previous_migration

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

Кроме этого, можно откатиться и к нулевой миграции, сделанной в начале создания приложения. Для этого используется команда manage.py migrate my_app zero .

Сложные случаи при миграциях

Уверен, что большинство из вас с описанными примерами уже так или иначе сталкивались. Но что делать в более сложных ситуациях? Попробуем разобрать наиболее распространенные варианты подобных проблем:

Представим, что в модели question с полем question_text нужно добавить title с описанием, какой длины должны быть данные в этом поле.

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

Есть несколько путей решения этой проблемы. Рассмотрим их.

  • Задать значение по умолчанию

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

Можно заполнить данные ранее созданных записей с помощью одноразовых значений. Для этого в консоли нужно прописать значение для заполнения таблицы по дефолту. В моем случае это default title :

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

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

На этом примере я прибавил поле с датой published_at , которому разрешено быть пустым. Для этого необходимо указать два параметра: null=True и blank=True .

При создании записи в таблице с question имеются как обязательные поля (например, question_text ), так и другие (в нашем случае published_at ). Последние благодаря отметке null=True будут заполнены со значением null — то есть они будут пустыми. Дополнять такие поля можно позже.

Также есть параметр blank=True . Если null отвечает за обращение внутри базы данных, то blank — за работу в админке Django. Даже при наличии поля null=True при создании записи административная панель не позволит сделать пустые записи без поля blank=True . С помощью этой метки мы можем создавать в админке такие поля.

  • Если не хочется ставить default или null

Иногда нецелесообразно или невозможно разрешить появление пустых полей — потому что это не логичное поведение моделей. Предположим, что у нас две модели: Question и Choice . Первая — для описания какого-то вопроса, вторая — для пула ответов на этот вопрос.

В какой-то момент вам нужно соединить чойсы с квесченами.

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

Самый простой способ — снести базу данных, удалить старые миграции, создать новую базу, внести необходимые изменения в модели и создать миграцию. Она задаст эти связи и каждый раз при заполнении базы данных все будет хорошо. Если же данные в этой базе очень важны, этот способ не подходит. Тогда следует создать дубликатную модель для модели Choice :

Я назвал ее QuestionChoice . Она состоит из choice_text и question с ForeignKey -связью на Question . Далее следует создать миграцию и мигрировать новую модель в базу данных, а затем создать дата-миграцию. По уже известной логике с ее помощью модель QuestionChoice будет заполняться данными с модели Choice и завязанными на каждый из этих записей ключами на записи в модели Question . После этого можно запускать дата-миграцию и использовать все эти изменения. Вам останется только удалить предыдущую модель Choice и произвести миграцию с переименованием модели-дубликата QuestionChoice в привычную Choice .

Дата-миграции

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

manage.py makemigrations --empty yourappname

В результате мы получаем миграцию в следующем виде:

Следующий шаг — заходим в середину пустой миграции и прописываем определенные данные для дата-миграции. Прежде всего, нужно прописать функцию с логикой, которая должна быть выполнена:

В моем случае возникла необходимость в создании и заполнении поля name , которое должно включать first_name и last_name из предыдущей модели. То есть мы создаем функцию и вызываем ее внутри оператора operations , запускаем миграции — и дальше Django все сделает сам.

Отмена дата-миграции

Иногда следует отменить или откатить созданную дата-миграцию. Но если использовать уже описанный выше механизм, появится следующий warning:

Причина этого — при создании миграции в автоматическом режиме внутри функции миграции создается зеркальная миграция отката.

Фактически появляются две миграции: одна — мигрирующая и другая — возвращающая значение назад. При создании и самостоятельном описании дата-миграции разработчикам не хочется писать много кода, поэтому большинство пренебрегает созданием обратной миграции. Поэтому и возникают сложности. Поэтому если вы знаете, что часто будете откатывать дата-миграцию, лучше пропишите функцию отката и укажите ее вторым параметром внутри функции RunPython внутри operations :

Повторный запуск дата-миграции

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

Благодаря указанию fake можно откатить дата-миграцию и запустить ее снова. Например, мы промигрировали в 8-ю миграцию, затем откатились назад в 7-ю с помощью фейковой миграции:

После отката с оператором fake вернулись на 7-ю миграцию, сделали определенные изменения в 8-й миграции и повторно запустили миграцию — и все сработает, как нужно:

Фейк-миграции

Хочу отдельно сосредоточить ваше внимание на понятии фейк-миграции.

У миграции есть два состояния:

  1. Существенная, которую можно увидеть внутри папки с файлами migrate (это те же файлы миграции).
  2. Запись в базе данных, где также содержится таблица со всеми миграциями, которые применили к БД.

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

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

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

Для этого используются следующие команды:

manage.py migrate --fake-initial manage.py migrate --fake myapp manage.py migrate --fake myapp migration_name

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

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

Squashing migrations

И напоследок расскажу о сквош-миграции. Этот инструмент позволяет сделать структуру миграций более лаконичной. При длительной разработке приложения может накапливаться 100, 200, 300 и более файлов с миграциями. Это не проблема для Django, он умеет работать с такой структурой. Но для программиста это все неудобно. Если у вас, скажем, 200 миграций, а нужно откатиться к сотой, а потом назад, то тяжело все отследить. Для сочетания и оптимизации миграций производят сквош-миграцию.

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

В этом случае Django сначала проанализирует все миграции, выполненные после указанной миграции (в моем примере — четвертой). Затем программа произведет их оптимизацию, посмотрит, какие действия выполнялись и противоречат ли они друг другу, скомпонует все в один файл и создаст сквош-миграцию:

После этого нужно выполнить фиксацию сквош-миграции. Здесь есть несколько шагов:

  • Удалите все миграционные файлы, которые включает сквош-миграция.
  • Обновите все миграции, которые зависели от сжатых и удаленных миграций.
  • Внесите изменения в атрибут Migration в классе сквош-миграции. Так мы скажем Django, что это сжатая миграция, и на нее нужно ориентироваться в будущем.

Вместо вывода

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

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Отмена последней миграции в Python

Undoing a database migration in Python.

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

Существует команда, которая позволяет отменить последнюю миграцию, и после ее применения можно просто удалить файл миграции. В Django, одном из самых популярных фреймворков Python, эту операцию можно выполнить при помощи команды migrate .

Пример отмены последней миграции

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

python manage.py migrate app_name 0003_previous_migration

В этом примере app_name — это имя приложения, для которого была выполнена миграция, а 0003_previous_migration — это имя предыдущей миграции, до которой необходимо откатиться.

Удаление файла миграции

После отмены миграции файл с ней можно просто удалить из каталога миграций.

rm app_name/migrations/0004_add_new_table.py

В этом примере команда rm служит для удаления файла, а app_name/migrations/0004_add_new_table.py — это путь к файлу миграции.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *