Я хотел бы поделиться одним из возможных способов переноса модели данных из одного приложения в другое.
Сразу отмечу, что этот вариант переноса модели данных не на 100% рабочий и может потребоваться дополнительная ручная правка таблиц для корректной установки Content Type. Так как любые подобные модификации чреваты потерей данных для отношений GenericForeignKey.
В моем случае GenericForeignKey не использовался, поэтому такой проблемы не было.
Исходные данные
Предположим, у вас есть старая статья article с моделью Article. Вам нужно создать приложение для блога и перенести модель статьи в это приложение. Использует базу данных PostgreSQL.
Перемещение модели
Сделайте резервную копию базы (backup), можете сделать дамп базы и потренироваться на этом дампе на сервере разработки.
Переместите код модели Article из article.models.py в blog.models.py . То есть код от старой модели надо убрать.
Измените класс Meta в модели Article , чтобы сохранить старое имя таблицы. В данном случае это была article_artilce
class Meta: db_table = 'article_article'
Изменить все ссылки на модели данных во всем проекте. Это означает изменение всего импорта и ForeignKey .
Создайте миграции для обоих приложений в следующем порядке.
python manage.py makemigrations blog python manage.py makemigrations article
Применить миграцию в поддельном режиме. Это позволит вам добавлять миграции по мере их применения, но никаких изменений вноситься не будет.
python manage.py migrate --fake
На данный момент база данных будет уязвима в том смысле, что она не была создана Тип контента для вашей переданной модели данных.Это можно исправить следующими действиями. Теперь нам нужно изменить имя таблицы, и это можно сделать, удалив db_table из модели данных и создав и применив новую миграцию к новому приложению. Тип контента будет создан автоматически при применении миграции.
python manage.py makemigrations blog python manage.py migrate
По сути, после этих действий база данных будет работать, а данные будут сохранены. Но вам могут потребоваться дополнительные шаги для настройки базы данных.
Очистка и корректировка базы данных
В зависимости от того, где и как использовалась переданная модель данных. Вам могут понадобиться некоторые действия. Например, корректировка Тип контента для GenericForeignKey .
У меня был самый простой случай — это удаление старого Content Type . Для этого нужно подключиться к базе данных и удалить информацию из всех таблиц, которые могут ссылаться на Content Type старой модели.
Такие таблицы могут быть:
- auth_user_user_permissions
- auth_permission
- django_content_type
- и т.д. другие модели, в которых можно было использовать старые модели до передачи
Я покажу пример старого Content Type из моей базы данных.
Процесс очистки
Подключиться к базе данных
sudo -u postgres psql \c myprojectdb
Давайте посмотрим на таблицу django_content_type, чтобы увидеть, какие идентификаторы имеют устаревший тип контента.
SELECT * FROM django_content_type;
Table outputid | app_label | model ----+------------------+----------------------- 1 | accounts | userprofile 2 | knowledge | section 3 | knowledge | article 4 | admin | logentry 5 | auth | permission 6 | auth | group 7 | auth | user 8 | contenttypes | contenttype 9 | sessions | session
Найдя старые id мы можем попробовать их удалить (например 50 и 51)
DELETE FROM django_content_type WHERE id BETWEEN 50 AND 51;
Если не получилось, то нужно найти, где используются данные ID. В ошибке будет указано, в каких таблицах они задействованы. В моем случае это были auth_permission и auth_user_user_permissions.
SELECT * FROM auth_permission WHERE content_type_id BETWEEN 50 AND 51;
Вывод таблицыid | name | content_type_id | codename -----+--------------------+-----------------+---------------- 154 | Can add chat | 50 | add_chat 155 | Can change chat | 50 | change_chat 156 | Can delete chat | 50 | delete_chat 157 | Can add message | 51 | add_message 158 | Can change message | 51 | change_message 159 | Can delete message | 51 | delete_message 276 | Can view Chat | 50 | view_chat 277 | Can view Message | 51 | view_message
Далее ищем интересующий id в auth_user_user_permissionsSELECT * FROM auth_user_user_permissions WHERE permission_id=154;
Вывод таблицыid | user_id | permission_id -----+---------+--------------- 102 | 2 | 154
Убираем из таблицы auth_user_user_permissions все разрешения для старого Content Type.
DELETE FROM auth_user_user_permissions WHERE permission_id=154;
Убираем разрешение из таблицы auth_permission.
DELETE FROM auth_permission WHERE content_type_id BETWEEN 50 AND 51;
Удалить типы контента.
DELETE FROM django_content_type WHERE id BETWEEN 50 AND 51;
Вывод
Таким способом можно переместить интересующую модель данных из одного приложения в другое, а также очистить базу от устаревшего контента. Однако работать с базой данных необходимо очень аккуратно, чтобы не нарушить ее целостность.
For Django, I recommend Timeweb VDS-server .
Дружище, ну подскажи. Совершенно не понял 7-й пункт. А именно, а что происходит с данными, которые в таблице? Или всё делалось, когда в таблице нет данных?
Дело в том, что у меня как раз похожая ситуация. Только нужно перенести три модели, в другое приложение. Понимаю, что всё начинается с одной. Но вот незадача. Все эти таблицы уже заполнены. И связь с этими данными уже достаточно прочная (по факту нужно перенесети каталог, из данных которого уже полно действующих заказов).
И вот мне не ясен такой момент. Вот была article_article. Я из META убираю строчку. Делаю makemigrations и migrate. Так и что происходит с таблицей? Она становиться новенькой, или просто переименовывается?
Я понимаю, что бэкапы и всё такое, но как-то честно сказать очково. Буду потом плясать с этим бэкапом.
Всё делалось, когда данные были в таблице. Сам очковал по полной, когда впервые так делал, раз на десять издевался над дампом на дев сервере, чтобы ничего не поломать.
Суть в том, что старая модель данных переносится в другое приложение, но с помощью db_table = 'article_article' старая таблица сохраняется.
Когда удаляется article_article то в миграции создаётся новое имя таблицы. То есть старая таблица переименовывается, а данные в ней сохраняются.
При этом в шаге 3 таблица условно была удалена из старого приложения, за счёт fake миграции. То есть информация о миграции добавилась, но при этом изменений не произошло.
А вот шаг 7 как раз переименовывает таблицу, чтобы она фактически лежала в новом приложении. Так что ДА - она переименовывается с сохранением данных.
Ну я на свой страх и риск, ночью всё попробовал локально, а потом уже удалил таблицы базы на сервере и залил обновлённый дамп. Спасибо большое. Инструкция реально помогла. Правда пришлось поплясать с сылками на разные роуты. Но оно того стоило. Порядок в папках и в базе радует глаз.
Сам долго колупал форумы, чтобы найти полноценное решение, как это сделать и ничего не поломать.
Иногда там ещё бывают циклические зависимости - вот это реально проблема. Но в итоге тоже нашёл решение через сброс всех миграций и создание одной initial миграции и применение её через fake. Подробнее в этой статье .
у меня была проблема что у меня в кубере автоматом миграция запускалась сделал так (как вариант решения, добовлял каждой миграции RunSQL):