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. Подробнее в этой статье .

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
АС
22 июля 2019 г. 16:32
Александр Спиридонов

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

  • Результат:46баллов,
  • Очки рейтинга-6
АС
22 июля 2019 г. 16:21
Александр Спиридонов

Qt - Тест 001. Сигналы и слоты

  • Результат:73баллов,
  • Очки рейтинга1
22 июля 2019 г. 10:00
Pavel K.

C++ - Тест 006. Перечисления

  • Результат:50баллов,
  • Очки рейтинга-4
Последние комментарии
21 июля 2019 г. 6:03
Евгений Легоцкой

да, наверное, 32-х разрядную поддержку уже давно поа было выкинуть. К слову, у вас много проектов под Android? Часто много где вижу вопросы о том, пишет ли кто-то вообще на Qt под мобильные сист…
20 июля 2019 г. 14:41
Андрей Янкович

Очень полезная информация, увы уже выкинул поддержку 32 битных бедняг.
20 июля 2019 г. 9:31
Михаиллл

Вот так qDebug()<<"position:"<<event->scenePos();
20 июля 2019 г. 8:49
Михаиллл

Добрый день. Как можно узнать координату на графической сцене при отпускании клавиши мыши?
Сейчас обсуждают на форуме
22 июля 2019 г. 10:50
Pavel K.

Благодарю.Буду пробовать.
22 июля 2019 г. 10:10
Pavel K.

Скорее всего в коде не правильно потоки используются. на форуме пишут кое что интересное - https://stackoverflow.com/questions/18112027/qt-5-1-qml-property-through-threads
22 июля 2019 г. 3:58
Евгений Легоцкой

Добрый день! Нужен совет сообщества по разработке функционала проверки орфографии. Одна из идей - добавить проверку орфографии при наборе текста статей. Полагаю, что наиболее аде…
22 июля 2019 г. 3:01
Евгений Легоцкой

Возможно, если при сохранении файла установить права доступа на файл. Что-то такое должно быть у QFile
Ищу работу?
5,000.00 руб. - 15,000.00 руб.
Дизайнер
Moskovskiy, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

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

EVILEG
О нас
Услуги
Присоединяйтесь к нам
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB