sql перенос данных из одной таблицы в другую
16 апреля 2016 г. 0:25
Возникла следующая проблема: для некоторого приложения нужно было удалить поле tags = TaggableManager(blank=True) (и соответственно зависимость django-taggit). Как обычно, стираю это поле и вызываю makemigration, который сделал своё дело как надо. Но при вызове migrate для другого проекта с тем же набором миграций происходит ошибка, что приложение taggit не найдено для выполнения миграций. Оно, конечно, и логично, что миграции будут требовать это приложение.
Сейчас я понимаю, что просто можно было поправить миграции, где создавалось поле taggit и где оно удалялось, поэтому если вы так не сделали и у вас изменилась структура данных таблицы, то ниже описанные действия могут помочь.
Перенос данных из таблицы разной структуры
Допустим, у нас есть приложение projects и таблица projects_project с полями:
- id
- link (ссылка на страницу проекта)
- title_in_link (показываемая подсказка при наведении на ссылку)
- order (путь до картинки)
- border_color (цвет границы)
- tags (теги)
Мы хотим следующую структуру:
- id
- link
- hint
- order
- is_border
- border_color
- border_width
Тем самым мы видим следующие изменения:
- title_in_link переименовался в hint.
- Добавилось поле is_boder, при этом оно обязательно для заполнения.
- border_width, которое может быть пустым.
- Удалилось поле tags
А теперь "вручную" исправим структуру таблицы:
- Переименовываем таблицу: projects_project -> projects_project_old.
- Удаляем все миграции приложения, а также удаляем соответствующие записи миграций в таблице django_migrations в базе данных.
Чтобы удалить миграции определённых приложений в базе данных, я обычно захожу в pgadmin, нажимаю просмотр данных таблицы django_migrations, ввожу условие фильтрации, например:
app = 'picture' OR app = 'gallery' OR app = 'file'
И удаляю все найденные строки.
- Вызываем makemigration для формирования 0001_initial.py (при этом понимаем, что придётся восстановить таблицу с помощью sql команд).
- Вызываем migrate и смотрим, что в базе данных создалась таблица projects_project с правильной структурой данных.
- Пишем sql код переноса данных из projects_project_old в projects_project:
INSERT INTO projects_project(id, link, hint, "order", is_border, border_color) select id, link, title_in_link, "order", 'FALSE', border_color from projects_project_old;
Проанализируйте пример: как видите, идёт соответствие полей для заполнения. В интернете качественного примера я не нашёл, поэтому-то и родился сей пост, чтобы это дело восполнить :)
Обратите внимание, что border_width мы можем не заполнять, так как оно может быть пустым, а is_border мы должны заполнить, но, так как у нас нет информации об этом поле, то самое простое - это заполнить значением FALSE для каждой записи. Как вариант потом можно написать django миграцию для заполнения полей TRUE или FALSE в зависимости от наличия какого-либо значения в поле border_color, но это уже другая история.
Ещё обратите внимание на то, что поле order совпадает со служебным словом sql, поэтому нужно это поле обособить двойными кавычками.
- Удаляем таблицу projects_project_old.
Вот, и всё. Ещё раз повторюсь, этот пример для тех, кто случайно сломал структуру данных таблицы, или миграции поломал или, таким образом как я, удалял зависимости от приложения. Это долгий "sql-ручной" путь исправления структуры, поэтому прежде чем удалять миграции, попробуйте их просто поправить :)
Перенос данных связанных таблиц
Допустим есть таблица: gallery и picture. Таблица picture содержит внешний ключ на таблицу gallery.
Этот случай немного по сложнее: при попытке выполнить 4 шаг описанный выше django скорее всего будет ругаться примерно так:
django.db.utils.ProgrammingError: relation "gallery_picture_6d994cdb" already exists
Для решения проблемы нужно переименовать индекс:
ALTER INDEX public.gallery_picture_6d994cdb RENAME TO gallery_picture_old_6d994cdb;
Это можно сделать через графический интерфейс pgadmin:
Нужный нам индекс выделен зелёным. Теперь правой кнопкой мыши по щелчку на индекс вызываем контекстное меню и выбираем свойства:
Здесь нужно переименовать индекс, например, дописав "_old".
Теперь снова пытаемся выполнить шаг 4 и далее следуем остальным выше описанным шагам.
Похожие статьи:
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0