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;
        ''')

    ]

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
m
  • molni99
  • 26 октября 2024 г. 1:37

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

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 1:29

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

  • Результат:20баллов,
  • Очки рейтинга-10

C++ - Тест 003. Условия и циклы

  • Результат:42баллов,
  • Очки рейтинга-8
Последние комментарии
i
innorwall8 ноября 2024 г. 8:51
Django - Урок 036. Как добавить аутентификацию через социальные сети. ВКонтакте buy priligy online usa In addition, it might not be effective at the doses recommended, because of your previous tolerance to a similar type of drug
i
innorwall8 ноября 2024 г. 7:40
Qt/C++ - Урок 039. Как закрасить строку в QSqlTableModel по значению в столбце priligy results This slowing of eGFR decline was observed in patients with and without low eGFR and in those with and without type 2 diabetes
i
innorwall8 ноября 2024 г. 2:45
QML - Урок 002. Custom Button in QML Android 2007; 14 2 270 83 priligy dapoxetine 60mg Testicular imaging is sort of a unique niche right now, Гў
i
innorwall8 ноября 2024 г. 1:32
C++ - Ускоряет ли сборку #pragma once? It could cause harm to the unborn baby buy generic priligy
Сейчас обсуждают на форуме
i
innorwall8 ноября 2024 г. 7:08
добавить qlineseries в функции School of Nursing, Long Island University, Brooklyn Campus, Brooklyn, NY, USA priligy dapoxetine 30mg
9
9Anonim25 октября 2024 г. 9:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов3 октября 2024 г. 4:05
Реализация навигации по разделам Спасибо Евгений!
F
Fynjy22 июля 2024 г. 4:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

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