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

Обновлено: 08.07.2024

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

  • Управление хранимыми процедурами (stored procedures)
  • Управление проверочными ограничениями (check constraints)
  • Импорт статических данных из файла
  • Запись операций миграции в лог

Давайте рассмотрим три возможных способа, сделать это максимально аккуратно.

1. Использовать миграции Django

Часто я нахожу, что разработчиков учат только тому, как использовать миграции Django для операций с моделями. Они могут знать некоторые SQL команды, но, поскольку они не используют их в Django, они предполагают, что миграции не могут напрямую использовать SQL команды. Но они могут! Многие из применений пользовательского кода SQL в стиле миграции, которые я видел, могли бы быть лучше реализованы в рамках миграций.

Давайте посмотрим на пример, который мы будем использовать для остальной части статьи. Представьте, что вы используете версию Django до 2.2, которая не поддерживает database check constraints. Вы можете добавить такое ограничение в таблицу базы данных используя следующий SQL:

Это ограничение заставит базу данных выдавать ошибку для любых строк, добавленных или обновленных в таблице myapp_book, у которых сумма percent_lovers и percent_haters не равна 100.

При использовании именования таблиц по умолчанию в Django таблица myapp_book будет создана для модели под названием Book внутри приложения myapp. Мы будем использовать эти имена и в этой статье.

Вышеприведенный SQL может быть выполнен с использованием django.db.connection:

Это работает, но это немного не типично. Вы можете запустить его с помощью manage.py shell или лучше в custom management (пользовательской команде управления) (подробнее об этом позже!).

Или вместо этого мы можем использовать миграцию.

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

Затем отредактируем этот файл миграции с использованием операции RunSQL:

Еще желательно переименовать файл миграции во что-то описательное. Например, вместо 0101_auto_20190715_1057.py мы могли бы переименовать в 0101_add_book_percentage_sum_constraint.py. Это очень поможет в долгосрочной перспективе.

Чтобы еще улучшить миграцию, мы можем добавить аргумент reverse_sql. Он говорит Django, как обратить вспять процесс миграции. Вам редко понадобится отменять миграцию, но когда вам это понадобиться… он реально спасет положение!

В нашем примере мы можем расширить операцию миграции до:

Это удалит проверочное ограничение при отмене операции.

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

Оценка данного подхода

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

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

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

2. Переопределение команды ‘migrate’

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

При запуске команды Django просматривает все приложения в INSTALLED_APPS, а затем в ядре. Первым делом он найдет пользовательскую команду управления с заданным именем. Таким образом, ваши приложения могут переопределять любые встроенные модули.

Чтобы переопределить migrate и добавить собственное поведение, вам нужно создать myapp/management/commands/migrate.py (заменив myapp именем одного из ваших приложений). Внутри этого файла вы можете создать подкласс встроенной команды migrate и добавить собственное поведение. Например:

Переопределение работает, потому что во всем коде Django миграция вызывается как команда, а не импортируется напрямую. Это делается с помощью функции call_command. Таким образом, если вы переопределили migrate, вызовется новая версия вместо основной.

Мы можем увидеть это в тестовом фреймворковом коде Django. Его функция setup_databases вызывает метод каждого соединения create_test_db. Они, в свою очередь, запускают call_command(‘migrate’) следующим образом:

Вы можете переопределить любую встроенную команду.

Оценка данного подхода

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

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

3. Добавление сигнала post_migrate

Django отправляет сигнал post_migrate в самом конце операций миграции. Вы можете увидеть это в исходном коде migrate .

Чтобы запустить какой-то дополнительный код на этом этапе, запишите его как обработчик сигнала. Зарегистрировать обработчика сигнала лучше всего в методе AppConfig.ready(), который Django будет вызывать во время инициализации.

Например, давайте посмотрим на Django contenttypes framework. Он импортируется из django.contrib.contenttypes. И использует обработчик сигнала post_migrate для создания одного экземпляра ContentType для каждой модели.

Обработчик определен в management/__init__.py. Это не самое описательное имя файла, содержащее обработчик сигнала — я обычно использую handlers.py в app. У фреймворка contenttypes есть это по историческим причинам.

В Django 2.2.3 create_contenttypes определяется следующим образом:

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

Интересно посмотреть на аргументы функции.

Обработчики сигналов вызываются только с ключевыми словами. Для прямой совместимости они должны принимать любые дополнения в конце в **kwargs, чтобы нераспознанные аргументы, добавленные отправителем, не нарушали обработчик — таким образом создается более слабая связь.

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

  • app_config — это текущий AppConfig — сигнал отправляется один раз для каждого приложения.
  • verbosity — текущий уровень ведения журнала.
  • interactive говорит нам, безопасно ли спрашивать пользователя о вводе.
  • using — псевдоним подключения к базе данных, который будет отличаться от DEFAULT_DB_ALIAS при использовании нескольких баз данных.
  • apps — реестр приложений, содержащий определенное состояние всех моделей после выполнения миграций. Поскольку пользователь, возможно, не выполнил каждую доступную миграцию, его следует использовать для доступа к классам моделей вместо прямого импорта.

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

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

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

Оценка данного подхода

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

Заключение

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

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

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

К счастью, Django, мои любимые батареи, включенные в стоимость, обрабатывают сложность довольно хорошо.

Джанго Модели помогают людям работать с данными таким образом, чтобы иметь смысл нашему мозгу Отказ И рамка предлагает множество классов, которые вы можете наследовать, чтобы помочь вам быстро развивать надежное приложение с нуля.

Что касается разработки на существующих приложениях Django, также есть функция для этого тоже.

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

Что под капотом

Migrations Django – это файлы Python, которые помогают вам добавлять и изменить вещи в таблицах базы данных, чтобы отразить изменения в ваших моделях Django.

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

Что такое таблица базы данных?

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

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

В Джанго каждая модель – это собственная таблица. Например, вот модель Django:

Каждое поле является столбцом, и каждая строка представляет собой экземпляр объекта Django этой модели.

1 Пластина Вилка Ложка

Джанго автоматически добавляет ID поле Если вы не укажете основной ключ.

Если вы хотели изменить имя вашей обедной модели, вы сделаете это в вашем Models.py код.

Django автоматически генерирует соответствующие файлы миграции. Соответствующая линия сгенерированных миграционных файлов в этом случае будет выглядеть:

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

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

… с таблицей базы данных, которая выглядела так:

1 Хлебная пластина Стекло Ложка Вилка Нож Пластина

Как манипулировать данными с миграциями Django

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

Существуют различные способы сделать это в зависимости от базы данных, которую вы используете. Как правило, вы можете найти инструкции, поиск и ключевые слова, такие как Резервное копирование , Восстановление или Снимок Отказ

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

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

Мы уже успешно переименовали нашу модель. Теперь мы переименуем поля, которые удерживают данные, которые мы хотим сохранить:

Django иногда достаточно умны, чтобы правильно определить старые и новые имена полей. Вас будет просить подтверждения:

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

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

Бег Макемиграция Снова теперь дает нам:

Вы закончили! Создавая миграции Django, вы успешно настроили свой Dinning_table и переместил существующие данные на новое место.

Дополнительная сложность

Вы заметите, что наш обеденный и ужин не очень сложен. Из Джанго много Варианты поля модели мы просто используем Шарфилд Отказ Мы также устанавливаем null = true Пусть Django хранит пустые значения как Null в базе данных.

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

Де-мистифицированные миграции

Я надеюсь, что эта статья помогла вам лучше понять миграции Django и как они работают!

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

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

Я использую Django1.7 с мезонином. Я создаю простой профиль (согласно документации мезонина), хранящийся в отдельном приложении "профили":

создание миграций возвращает:

когда я запускаю "перенести профиль":

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

что я сделал не так?

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

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

в противном случае вы получите ошибку no-such-table:)

[edit] вы очистили таблицу applied-migrations? Это также распространенная причина неприменимых миграций.

  1. в базе данных MySQL удалить строку 'profiles' из таблицы 'django_migrations' .
  2. удалить все файлы миграции в папке migrations.
  3. попробовать еще раз python manage.py makemigrations и .

Я новичок Django, и я проходил через ту же проблему. Эти ответы не сработали для меня. Я хотел поделиться тем, как я решил проблему, возможно, это сэкономит кому-то много времени.

я делаю изменения в модели, и я хочу применить эти изменения к БД.

что я сделал:

запустить на shell:

что получилось:

никакие изменения не сделаны в DB

но когда я проверяю схему БД, она остается старой

причина:

  • когда я запускаю python manage.py migrate app-name , Django проверяет таблицу django_migrations в БД, чтобы узнать, какие миграции уже применены и пропустит эти миграции.

удалить запись с app= "my-app-name" из этой таблицы ( delete from django_migrations where app = "app-name" ). Очистить папку миграции и запустить python manage.py makemigration my-app-name , потом python manage.py migrate my-app-name . Это было предложено большинством проголосовавших. Но это тоже не работает.

почему?

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

Решение 1:

удалить существующую таблицу (с старая схема), сделать начальные миграции и применить снова. Это будет работать (это сработало для меня), так как у нас есть "начальная миграция", и в нашей БД не было таблицы с тем же именем. (Совет: я использовал python manage.py migrate my-app-name zero чтобы быстро отбросить таблицы в БД)

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

решение 2:

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

изменить models.py чтобы соответствовать текущей таблице в вашей базе данных

удалить все файлы в "миграции"

Run python manage.py makemigrations your-app-name

удалить в django_migrations все поля с django_migrations.app = ваше-app-имя Как это сделать, зависит от того, какую БД вы используете Пример для MySQL: delete from django_migrations where app = "your-app-name";

изменить models.py чтобы соответствовать новой схеме (e.Я. схема, которая вам сейчас нужна)

сделайте новую миграцию, запустив python manage.py makemigrations your-app-name

Run python manage.py migrate your-app-name

это работает для меня. И мне удалось сохранить существующие данные.

причина, по которой я прошел через все эти проблемы, заключалась в том, что я удалил файлы в some-app / migrations/ (файлы миграций). И, следовательно, эти файлы миграции и моя база данных не согласуются друг с другом. Поэтому я бы попытался не изменять эти файлы миграции, если я действительно не знаю, что я делаю.

1-запустить python manage.py makemigrations

теперь все изменения применяются к вашей БД

в моем случае я писал так:

python manage.py makemigrations --пустой yourappname

python manage.py migrate yourappname

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

DELETE FROM django_migrations WHERE app=' your-app-name '

python manage.py makemigrations python manage.py migrate

это сделает вашу миграцию поддельной. Теперь вы можете запустить скрипт миграции

таблицы будут созданы, и вы решили свою проблему.. Ура.

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

@phanhuy152 имеет лучший ответ. Просто чтобы добавить мои два цента:

его решение имеет вид:

  1. удалить историю миграции в DB
  2. удалить migrations папку
  3. изменить модель в соответствии с БД до изменений
  4. makemigrations для восстановления начального состояния файлов миграции
  5. затем измените модель, как вам нравится
  6. makemigrations снова
  7. migrate применить обновления к столу.

но в моем случае, у меня есть несколько моделей в models.py файл и на последнем шаге, Django жалуется на Table xxx already exists , потому что начальные файлы миграции намереваются создать таблицу xxx снова, когда мы просто не (и не хотим)отбрасывать другие таблицы.

в этом случае, чтобы сохранить данные, мы должны сказать Django оставить их в покое в migrate . Мы просто делаем: (предположим, что класс A-это тот, который мы меняем, а класс B, C остается же):

добавьте эти строки после того, как мы построим начальные миграции.

Итак, процесс теперь:

  1. .
  2. .
  3. .
  4. .
  5. добавить managed = False в другие классы
  6. makemigrations применить Meta изменения. Вы увидите что-то вроде:
  1. migrate применить их в БД
  2. теперь измените модель: добавьте поле, измените тип и т. д.
  3. migrate снова.
  4. удалить Meta класс, чтобы позволить Django снова управлять другим классом. makemigrations , migrate снова.

теперь у вас есть вся структура и данные ваших моделей, без потери части, ранее хранившейся в БД.

проблема здесь в поддельных миграциях где-то. В основном в вашей базе данных таблица, созданная из вашей модели, не существует, но где-то во времени эта таблица существовала раньше из-за старого обновления, каким бы оно ни было. Проблема в том, что django уже сделал эти миграции, поэтому таблицы должны существовать для, следовательно, игнорируя миграции, но получая ошибку "table_doesnt_exist" в Admin.

1.- Не забудьте сохранить любые данные из этой модели.

2.- Доступ к базе данных и выполнения запроса.

3.- Получить id из списка, созданного из запроса. Это миграции, которые Django перенесла до сих пор, поэтому таблицы должны существовать. В вашем случае я бы искал строку с именем roadmapprofile, из-за этого-название модели.

4.- Теперь давайте удалим эту строку из этой таблицы с помощью идентификаторов,

заменить value_id1 и value_id2 на соответствующие идентификаторы. Это может быть только один или много, поэтому не волнуйтесь, если вы не видите более 1 id, это означает, что только одна модель существует в текущем приложении.

5.- Миграция приложения до нуля

6.- Удалить все файлы миграции в папке миграции приложений

7.- Создать Миграции

8.- Как только вы удалите эти реестры и запустите manage.py migrate; Django будет вынужден выполнять миграции для ваших моделей из-за " миграции Не существует " для этой модели.

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

Создание миграций возвращает:

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

Что я сделал не так?

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

«Это сделает новую начальную миграцию для вашего приложения. Теперь, когда вы запустите миграцию, Django обнаружит, что у вас есть начальная миграция и что таблицы, которые он хочет создать, уже существуют, и отметят миграция уже применяется . "

@ phanhuy152 имеет лучший ответ. Просто, чтобы добавить мои два цента:

  1. Удалить историю миграции в БД
  2. Удалить папку migrations
  3. Отредактируйте вашу модель, чтобы она соответствовала БД до вашего изменения
  4. makemigrations для восстановления исходного состояния файлов миграции
  5. Затем измените модель, как вам нравится
  6. makemigrations снова
  7. migrate чтобы применить обновления к таблице.

Но в моем случае у меня есть несколько моделей в файле models.py , и на последнем шаге Джанго жалуется на Table xxx already exists , потому что файлы начальной миграции намереваются снова создать таблицу xxx, когда мы просто не t (и не хочу) отбрасывать другие таблицы.

В этом случае, чтобы сохранить данные, мы должны сказать Django оставить их в покое migrate . Мы просто делаем: (предположим, что класс A - это тот, который мы меняем, а класс B, C остаются прежними):

Добавьте эти строки после того, как мы создадим начальные миграции.

Итак, процесс сейчас таков:

  1. .
  2. .
  3. .
  4. .
  5. Добавьте managed = False к другим классам
  6. makemigrations чтобы применить Meta изменения. Вы увидите что-то вроде:
  1. migrate чтобы применить их в БД
  2. Измените свою модель сейчас: добавьте поле, измените тип и т. Д.
  3. migrate снова.
  4. Удалите класс Meta , чтобы позволить Django снова управлять другим классом. makemigrations , migrate снова.

Теперь у вас есть вся структура и данные ваших моделей, без потери части, ранее сохраненной в БД.

1 - запустить питон manage.py makemigrations

Теперь все изменения применяются к вашей БД

Это сделает вашу миграцию подделкой. Теперь вы можете запустить скрипт миграции

Таблицы будут созданы, и вы решили свою проблему .. Ура .

В моем случае я написал так:

python manage.py makemigrations - пусто yourappname

python manage.py migrate yourappname

Django отслеживает все примененные миграции в таблице django_migrations. Поэтому просто удалите все строки в таблице django_migrations, которые связаны с вашим приложением, например:

DELETE FROM django_migrations WHERE app=' ваш - приложение - имя '

А затем сделать:

python manage.py makemigrations python manage.py migrate

Возможно, ваша модель не связана, когда процесс миграции продолжается. Попробуйте импортировать его в файл urls.py from models import your_file

У меня была такая же проблема. Убедитесь, что папка миграций приложения создана (YOURAPPNAME / migrations). Удалите папку и введите команды:

Я вставил эти строки в каждый класс в models.py:

Это решило мою проблему.

  1. В базе данных MySQL удалите строку 'profiles' из таблицы 'django_migrations' .
  2. Удалите все файлы миграции в папке миграции.
  3. Попробуйте еще раз python manage.py makemigrations и python manage.py migrate команду.

Проблема здесь в фальшивых миграциях где-то. По сути, в вашей базе данных таблица, созданная из вашей модели, не существует, хотя где-то во времени эта таблица существовала раньше, из-за старого обновления, каким бы оно ни было. Проблема заключается в том, что django уже выполнил эти миграции, поэтому таблицы ДОЛЖНЫ существовать, следовательно, с пропуском миграций, но с ошибкой "table_doesnt_exist" в Admin.

1.- Обязательно сохраните все данные из этой модели.

2.- Доступ к вашей базе данных и выполнить этот запрос.

3.- Получить идентификатор из списка, сгенерированного из запроса. Это миграции, которые Django уже перенес, поэтому ТАБЛИЦЫ ДОЛЖНЫ СУЩЕСТВОВАТЬ. В вашем случае я бы искал строку с именем roadmapprofile , потому что это имя вашей модели.

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

Замените value_id1 и value_id2 соответствующими идентификаторами. Это может быть только один или несколько, поэтому не беспокойтесь, если вы не видите более 1 идентификатора, это означает, что в текущем приложении существует только одна модель.

5.- Перенос приложения на ноль

6.- Удалите все файлы миграции в папке миграций приложения.

7.- Создание миграций

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

Читайте также: