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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Как стать автором?

Внесите вклад в развитие сообщества EVILEG.

Узнайте, как стать автором сайта.

Изучить
Donate

Добрый день, Дорогие Пользователи !!!

Я Евгений Легоцкой, разработчик EVILEG. И это мой хобби-проект, который помогает учиться программированию другим программистам и разработчикам

Если сайт помог вам, и вы хотите также поддержать развитие сайта, то вы можете сделать пожертвование следующими способами

PayPalYandex.Money
Timeweb

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг Timeweb
5 июня 2020 г. 23:20
Алексей

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60баллов,
  • Очки рейтинга-1
5 июня 2020 г. 23:15
Алексей

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

  • Результат:53баллов,
  • Очки рейтинга-4
V
5 июня 2020 г. 16:47
Vladzo

C++ - Тест 005. Структуры и Классы

  • Результат:83баллов,
  • Очки рейтинга4
Последние комментарии
6 июня 2020 г. 15:13
Владислав Меленчук

Как установить и настроить Django JET

Можно использовать six и оттуда импортировать unicode. Я так решил проблему) Но всё равно откатился обратно на админку джанги.
6 июня 2020 г. 11:20
BL4CK R4BBIT

Как установить и настроить Django JET

на Django >3+ работать не будет. Либо придется лезть внутрь и переопределять метод unicode . Либо писать декоратор
5 июня 2020 г. 10:52
progammist

Распознавание изображений на Python с помощью TensorFlow и Keras

Огромное спасибо за метериал, по-больше бы подобных статей (с подробным описанием работы и примерами применения) на тему современных технологий. Вопрос поразмышлять. На текущий момент реал…
5 июня 2020 г. 1:39
Евгений Легоцкой

Qt/C++ - Урок 091. Как написать кастомный делегат управляющий подсветкой строки в таблице

По-моему, смысла в этом нет особого. Если делегат будет игнорировать настройки таблицы, то это приведёт ещё к большему непониманию, что вообще происходит, для программиста, который после вас буд…
5 июня 2020 г. 1:34
IscanderChe

Qt/C++ - Урок 091. Как написать кастомный делегат управляющий подсветкой строки в таблице

Сижу, размышляю: можно ли переписать делегата так, чтобы независимо от настроек строк выделялись строки?
Сейчас обсуждают на форуме
u
6 июня 2020 г. 7:26
ubomj

Галерея изображений

delete
s
6 июня 2020 г. 1:54
shuric

Qt/C++ Определение положения курсора над действие(кнопкой) в QToolBar

Доброго дня. Возник вопрос - как можно определить что курсор находится над определенным действием(кнопкой) в qtoolbar ? mainwindow.cpp MainWindow::MainWi…
s
6 июня 2020 г. 0:45
shuric

Qt/C++ особенности QProxyStyle

Да, Вы правы. Код был скопирован с сайта (уже не помню с какого), но решил пойти по пути более легком. Пришлось переписать - кому интересно: использовал stackedWidget для пе…
5 июня 2020 г. 23:08
Алексей

Посоветуйте новичку (базы данных и Qt, что учить)

Блин, а я недавно купил Шлее Qt 5.10 :( С детства хотел стать программистом, баловался Паскалем, писал простенькие программки на Delphi, создавал движок на php, изучал C (забросил и перешел на п…
5 июня 2020 г. 13:09
IscanderChe

QPlainTextEdit настройка цвета фона

Вечер добрый. Пытаюсь настроить цвет фона QPlainTextEdit следующим образом: CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent){ ... QPalette::ColorRole role = bac…
О нас
Услуги
© EVILEG 2015-2020
Рекомендует хостинг TIMEWEB