Django загрузка данных из устройства после обратной миграции /loaddata использует схему модели, а не схему базы данных
Недавно я столкнулся с проблемой при импорте более старых данных, чем моя нынешняя модель. Поток, который я использую и приводя к ошибке:
- dumpdata с python manage.py dumpdata → 0002
- внести некоторые изменения в модель
- создать миграцию с помощью python manage.py schemamigration app_name --auto → 0003
- выполнить миграцию
- играть с базой данных
- перейти на 0002
- loaddata генерирует SQL, в котором у меня есть текущие (миграция 0003) поля, и вызывают сбои процесса loaddata (добавлено поле mpoly)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/postgresql_psycopg2/base.py",
строка 44, в исполнении return self.cursor.execute(query, args) DatabaseError: столбец "mpoly" отношения "localization_province" делает не существует LINE 1:... e "(" id "," name "," slug "," mpoly ") V...
- комментируя изменения в models.py, сделанные до 0003, заставьте все работать нормально
Есть ли способ избежать игры с моделями после обратной миграции, если я хочу загрузить данные?
Может, мне не хватает чего-то действительно очевидного...
PS: Я использую South 7.3, Django 1.2.3 и PostgreSQL 8.4 в качестве базы данных.
Ответы
Ответ 1
Alex Vidal предложил хорошее быстрое решение для этого, когда он укусил нас на нашей работе. Для этого требуется библиотека Gary Bernhardt Dingus. Как только у нас будет время, мы рассмотрим зависимость Dingus и отправим запрос на тягу на юг, но если вы находитесь в привязке прямо сейчас, это может вывести вас из себя:
from dingus import patch
def loaddata(orm, fixture_name):
_get_model = lambda model_identifier: orm[model_identifier]
with patch('django.core.serializers.python._get_model', _get_model):
from django.core.management import call_command
call_command("loaddata", fixture_name)
Использование:
from apps.common.utils import loaddata
class Migration(DataMigration):
def forwards(self, orm):
loaddata(orm, "initial_fjords.json")
Мы тестировали только в Django 1.3. Изменить: я проверил историю Django _get_model
, и это должно работать с Django 0.95 и выше.
Ответ 2
Я нахожу, что лучше всего держать любые приспособления, которые у меня есть, в соответствии с текущей версией кода. Поэтому при создании миграции 0003 вы выполняете перенос данных и новый dumpdata
, заменяющий прибор 0002. Когда вы создаете миграцию данных, убедитесь, что вы сделайте как вперед, так и назад, таким образом, вы вернете правильные данные при переходе на 0002.
Когда вы выполняете миграцию данных, убедитесь, что вы просматриваете все модели с помощью объекта orm
, в противном случае вы получите ошибки, аналогичные тем, что вы уже испытываете.
Если вы хотите запустить код django со старыми данными (версия 0002) по какой-то причине, ваши модели должны соответствовать вашей базе данных. Это означало бы проверку соответствующей версии кода с использованием любого используемого вами кода, который вы используете (git, hg, svn...). Если вы пытаетесь решить проблему "назад во времени", вы, вероятно, захотите также разветкиться в этой точке.
См. также южные комментарии к документации по светильникам
Здесь идея, вдохновленная этой ссылкой выше: "самое лучшее, что нужно сделать, это написать новую миграцию для загрузки прибора в". Как насчет загрузки вашего приспособления (которое у вас уже есть) из миграции, а не loaddata
. Вам все равно необходимо создать миграцию данных и использовать объект orm
для ручной загрузки данных. Вы можете использовать функции django сериализации, что как раз то, что loaddata
это.
В отношении того, почему loaddata
использует версию модели, а не версию базы данных: loaddata
является командой управления django, без знание того, что делает юг. Из-за этого он должен оставаться агностиком базы данных и использовать django ORM. Вы всегда можете написать свою собственную команду управления, если вам нужно сделать что-то более конкретное - потенциально вытащить некоторые версии управления версиями на юг orm или сделать конкретную базу данных loaddata, которая считывает схему непосредственно из базы данных. Я думаю, что решение в предыдущем абзаце будет намного меньше работать.
Ответ 3
Поздно к обсуждению, но надеюсь, что это будет полезно. На самом деле у вас есть два подхода, которые вы можете предпринять:
-
Загрузите данные на ранней стадии в своих миграциях, а затем используйте данные
миграции, чтобы изменить его при каждом переносе схемы. Это имеет то преимущество, что вы проверяете миграцию данных, когда идете.
-
Загрузите данные как инструмент, который всегда будет использовать ваши текущие модели
и поэтому вам необходимо постоянно обновлять свои светильники.
В дополнение к вышеприведенным подходам вы можете загружать данные, используя dumpscript (доступный как часть django-command-extensions), чтобы выгрузить ваше устройство в python. Оттуда вам нужно отредактировать прибор, чтобы использовать ORM, доступную в процессе миграции, а не ваши модели Django. Это обычно наиболее полезно, если у вас слишком много данных.
Смотрите: http://south.aeracode.org/attachment/ticket/1010/fixtures.diff