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