Evgenii Legotckoi
Evgenii Legotckoi24 апреля 2019 г. 3:42

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

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

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

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


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

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

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

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

  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

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

  7. Это можно исправить следующими действиями. Теперь нам нужно изменить имя таблицы, и это можно сделать, удалив 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 из моей базы данных.

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

  1. Подключиться к базе данных

    sudo -u postgres psql
      \c myprojectdb

  2. Давайте посмотрим на таблицу django_content_type, чтобы увидеть, какие идентификаторы имеют устаревший тип контента.

    SELECT * FROM django_content_type;

    Table output
    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 все разрешения для старого Content Type.

    DELETE FROM auth_user_user_permissions WHERE permission_id=154;

  6. Убираем разрешение из таблицы auth_permission.

    DELETE FROM auth_permission WHERE content_type_id BETWEEN 50 AND 51;

  7. Удалить типы контента.

    DELETE FROM django_content_type WHERE id BETWEEN 50 AND 51;

Вывод

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

For Django, I recommend Timeweb VDS-server .

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

Вам это нравится? Поделитесь в социальных сетях!

Макар Карабасов
  • 1 июля 2019 г. 17:45

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

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

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

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

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

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

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

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

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

Макар Карабасов
  • 2 июля 2019 г. 4:56

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

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

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

bernar92
  • 9 ноября 2021 г. 0:46
  • (ред.)

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

operations = [
        migrations.RunSQL('''
            ALTER TABLE IF EXISTS credits_operatorcreditapplication RENAME TO operator_creditapplication;
            create table credits_operatorcreditapplication();

            delete from auth_group_permissions
            USING (select *
                   from auth_permission
                   join django_content_type dct on dct.id = auth_permission.content_type_id
            ) dct
            where dct.app_label='credits' and dct.model='operatorcreditapplication';

            DELETE FROM auth_permission
            USING django_content_type
            where django_content_type.app_label='credits' and django_content_type.model='operatorcreditapplication';

            DELETE FROM django_admin_log
            USING django_content_type
            where django_content_type.app_label='credits' and django_content_type.model='operatorcreditapplication';

            DELETE FROM django_content_type WHERE app_label='credits' and model='operatorcreditapplication';
        '''),
        migrations.DeleteModel(
            name='OperatorCreditApplication',
        ),
    ]



operations = [
        migrations.CreateModel(
            name='OperatorCreditApplication',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Время создания')),
                ('changed_at', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Время последнего изменения'))
            ],
            options={
                'verbose_name': '....',
                'verbose_name_plural': '...',
                'ordering': ('created_at'),
            },
        ),
        migrations.RunSQL('''
            DROP TABLE IF EXISTS scoring_operatorcreditapplication;
            ALTER TABLE IF EXISTS operator_creditapplication RENAME TO scoring_operatorcreditapplication;
        ''')

    ]

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
d
  • dsfs
  • 26 апреля 2024 г. 11:56

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

  • Результат:80баллов,
  • Очки рейтинга4
d
  • dsfs
  • 26 апреля 2024 г. 11:45

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

  • Результат:50баллов,
  • Очки рейтинга-4
d
  • dsfs
  • 26 апреля 2024 г. 11:35

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

  • Результат:73баллов,
  • Очки рейтинга1
Последние комментарии
k
kmssr9 февраля 2024 г. 2:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 9:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 18:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 16:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 декабря 2023 г. 5:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
Gar22 апреля 2024 г. 12:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 апреля 2024 г. 14:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 апреля 2024 г. 13:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 9:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 11:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Следите за нами в социальных сетях