Django - Урок 045. Перемещение моделей из одного приложения в другое

Django, Application, Model

Хотелось бы поделиться одним из возможных вариантов перемещения модели данных из одного приложения в другое.

Сразу отмечу, что данный вариант переноса модели данных не является стопроцентно рабочим и может понадобиться дополнительное ручное редактирование таблиц для правильной установки Content Type. Поскольку любые подобные модификации чреваты потерей данных для GenericForeignKey отношений.

В моём случае GenericForeignKey не использовались, поэтому такой проблемы не возникло.

Исходные данные

Допустим, у вас имеется старое приложение article, в котором есть модель Article. Вам нужно создать приложение blog и перенести модель Article в данное приложение. Используется база данных PostgreSQL.

Перемещение модели

  1. Сделать резервную копию базы данных (backup), можете сделать дамп базы данных и потренироваться на данном дампе на development сервере.

  2. Перенести код модели Article из article.models.py в blog.models.py . То есть код из старой модели необходимо удалить.

  3. Отредактировать класс Meta в модели Article , чтобы сохранить старое название таблицы. В данном случае оно было article_artilce

    class Meta:
          db_table = 'article_article'

  4. Изменить все ссылки на модели данных во всём проекте. Это означаете поменять все импорты и ForeignKey .

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

    python manage.py makemigrations blog
      python manage.py makemigrations article

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

    python manage.py migrate --fake

    В данный момент база данных будет уязвима в том плане, что не был создан Content Type для вашей перенесённой модели данных.

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

    python manage.py makemigrations blog
      python manage.py migrate

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

Чистка базы данных и корректировка

В зависимости от того, где и как использовалась перенесённая модель данных. Могут понадобиться те или иные действия. Например корректировка Content Type для GenericForeignKey .

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

Такими таблицами могут быть:

  • auth_user_user_permissions
  • auth_permission
  • django_content_type
  • и т.д. остальные модели, в которых могли использоваться старые модели до переноса

Я покажу на примере старых Content Type из своей базы данных.

Процесс чистки

  1. Подключимся к базе данных
    sudo -u postgres psql
      \c myprojectdb
  2. Посмотрим таблицу django_content_type, чтобы понять, какие id имеют устаревшие Content Type.

    SELECT * FROM django_content_type;

    Вывод таблицы
    id |    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

  3. Найдя старые id можем попытаться их удалить (Например 50 и 51)

    DELETE FROM django_content_type WHERE id BETWEEN 50 AND 51;

  4. Если не получилось, то нужно найти, где используются данные 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_permissions
    SELECT * FROM auth_user_user_permissions WHERE permission_id=154;

    Вывод
    id  | user_id | permission_id
      -----+---------+---------------
      102 |       2 |           154

  5. Удаляем из таблицы auth_user_user_permissions все permission для старого Content Type.

    DELETE FROM auth_user_user_permissions WHERE permission_id=154;

  6. Удаляем из таблицы auth_permission сами permission.

    DELETE FROM auth_permission WHERE content_type_id BETWEEN 50 AND 51;

  7. Удаляем Content Types.

    DELETE FROM django_content_type WHERE id BETWEEN 50 AND 51;

Заключение

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

Для Django рекомендую VDS-сервера хостера Timeweb .

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

Дружище, ну подскажи. Совершенно не понял 7-й пункт. А именно, а что происходит с данными, которые в таблице? Или всё делалось, когда в таблице нет данных?

Дело в том, что у меня как раз похожая ситуация. Только нужно перенести три модели, в другое приложение. Понимаю, что всё начинается с одной. Но вот незадача. Все эти таблицы уже заполнены. И связь с этими данными уже достаточно прочная (по факту нужно перенесети каталог, из данных которого уже полно действующих заказов).

И вот мне не ясен такой момент. Вот была article_article. Я из META убираю строчку. Делаю makemigrations и migrate. Так и что происходит с таблицей? Она становиться новенькой, или просто переименовывается?

Я понимаю, что бэкапы и всё такое, но как-то честно сказать очково. Буду потом плясать с этим бэкапом.

Всё делалось, когда данные были в таблице. Сам очковал по полной, когда впервые так делал, раз на десять издевался над дампом на дев сервере, чтобы ничего не поломать.

Суть в том, что старая модель данных переносится в другое приложение, но с помощью db_table = 'article_article' старая таблица сохраняется.

Когда удаляется article_article то в миграции создаётся новое имя таблицы. То есть старая таблица переименовывается, а данные в ней сохраняются.

При этом в шаге 3 таблица условно была удалена из старого приложения, за счёт fake миграции. То есть информация о миграции добавилась, но при этом изменений не произошло.

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

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

Сам долго колупал форумы, чтобы найти полноценное решение, как это сделать и ничего не поломать.

Иногда там ещё бывают циклические зависимости - вот это реально проблема. Но в итоге тоже нашёл решение через сброс всех миграций и создание одной initial миграции и применение её через fake. Подробнее в этой статье .

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Ищу работу?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы

ДШ
21 сентября 2019 г. 14:55
Дмитрий Шилков

C++ - Тест 001. Первая программа и типы данных

  • Результат:46баллов,
  • Очки рейтинга-6
s
18 сентября 2019 г. 17:19
sanyalitv

C++ - Тест 002. Константы

  • Результат:33баллов,
  • Очки рейтинга-10
s
18 сентября 2019 г. 17:12
sanyalitv

C++ - Тест 001. Первая программа и типы данных

  • Результат:80баллов,
  • Очки рейтинга4
Последние комментарии
M
20 сентября 2019 г. 11:25
Mark

вызываю метод get у m_downloader в другом методе и приложение начинает вылетать. В чем ошибка?
M
19 сентября 2019 г. 5:45
Mark

А вот как выгрузить файл на сервер по http протоколу? Допустим на regRu. И как получить путь файла, которой отображается в файловом менеджере regRu, чтобы загрузить его.
17 сентября 2019 г. 6:07
Misha Lebedev

Кстати интересные темы нашёл тут https://emacsway.github.io/ru/django-framework/#django-models Может что полезного тоже Евгений найдёте
17 сентября 2019 г. 4:50
Misha Lebedev

Доброго времени суток. Спасибо за хороший ответ, У меня ситуация така что в галлереи будет несколько миллионов фотографий с фильтрами и тегами , и я опасаюсь за производительност . Это ос…
17 сентября 2019 г. 3:23
Евгений Легоцкой

Добрый день. Да, я тоже читал ту статью в своё время и согласен с тем, что внешние ключи гораздо лучше, чем GenericForeignKey. Выборки в ряде случае работают быстрее. Но лично мне про…
Сейчас обсуждают на форуме
C
21 сентября 2019 г. 13:58
Cobra91151

Здравствуйте! Как вариант могу вам посоветовать QFtp класс, с помощью него можна просматривать, удалять, переименовывать и т.д файлы на сервере через клиентское ПО. Если вас такое интересу…
МС
21 сентября 2019 г. 12:51
Михаил Сермяжко

Так работает import QtQuick 2.7import QtQuick.Window 2.2import QtQuick.Controls 2.0Window { id: demo width: 800 height: 600 visible: true color: "#ff303030" prope…
МС
21 сентября 2019 г. 11:46
Михаил Сермяжко

Говорят через делегат должно работать: ListView{ id:l anchors.fill: parent model: ["data 1","data 2","data 3"] currentIndex : 2 delegate: Text { Rectangle{ …
C
21 сентября 2019 г. 9:08
Cobra91151

Здравствуйте! Я хочу подключатся к сетям WiFi Enterprise через свою программу. Настроил Radius Server, поключение к сети через Windows работает. Но при подключении через программу пишет: о…
20 сентября 2019 г. 4:56
Pavel K.

Привет , подскажите кто-нибудь , как сделать драг н дроп , не нарушая при этом логику работы зума? import QtQuick 2.6 import QtGraphicalEffects 1.0 Page { id:win property string fi…
EVILEG
О нас
Услуги
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB