Как правильно загрузить светильники в Джанго на юг?
Я использую Django 1.5b1 и южную миграцию, и жизнь в целом была великолепной. У меня есть некоторые обновления схемы, которые создают мою базу данных, в том числе таблицу пользователей. Затем я загружаю приспособление для ff.User
(моя пользовательская модель пользователя):
def forwards(self, orm):
from django.core.management import call_command
fixture_path = "/absolute/path/to/my/fixture/load_initial_users.json"
call_command("loaddata", fixture_path)
Все работало отлично, пока я не добавил еще одно поле в мой ff.User
модель, гораздо дальше по линии миграции. Моя нагрузка на прибор теперь ломается:
DatabaseError: Problem installing fixture 'C:\<redacted>create_users.json':
Could not load ff.User(pk=1): (1054, "Unknown column 'timezone_id' in 'field list'")
Часовой пояс - это поле (ForeignKey), которое я добавил в свою модель пользователя.
Ff.User отличается от того, что находится в базе данных, поэтому Django ORM сдается с ошибкой БД. К сожалению, я не могу указать свою модель в своем приборе как orm['ff.User']
, который, кажется, южный способ делать вещи.
Как правильно загружать приборы, используя юг, чтобы они не ломались после модификации моделей, для которых предназначены эти приборы?
6 ответов
Чтение следующих двух постов помогло мне найти решение:
http://andrewingram.net/2012/dec/common-pitfalls-django-south/
http://news.ycombinator.com/item?id=4872596
В частности, я переписал свои миграции данных, чтобы использовать вывод из 'dumpscript'
Мне нужно было немного изменить полученный скрипт для работы с югом. Вместо того чтобы делать
from ff.models import User
я делаю
User = orm['ff.User']
Это работает точно так, как я хотел. Кроме того, он имеет преимущество, заключающееся в отсутствии жесткого кодирования идентификаторов, как это требуется для приборов.
Я нашел фрагмент Django, который делает эту работу!
https://djangosnippets.org/snippets/2897/
Он загружает данные в соответствии с моделями, замороженными в приборе, а не с фактическим определением модели в коде ваших приложений! Идеально подходит для меня.
Я предложил решение, которое может вас заинтересовать:
По сути, вот как я загружаю свой прибор:
from south.v2 import DataMigration
import json
class Migration(DataMigration):
def forwards(self, orm):
json_data=open("path/to/your/fixture.json")
items = json.load(json_data)
for item in items:
# Be carefull, this lazy line won't resolve foreign keys
obj = orm[item["model"]](**item["fields"])
obj.save()
json_data.close()
Самое элегантное решение, которое я нашел, здесь, где ваши модели приложений get_model
функция отключена, чтобы вместо этого поставлять модель из поставляемой формы. Затем он устанавливается обратно после применения прибора.
from django.db import models
from django.core.management import call_command
def load_fixture(file_name, orm):
original_get_model = models.get_model
def get_model_southern_style(*args):
try:
return orm['.'.join(args)]
except:
return original_get_model(*args)
models.get_model = get_model_southern_style
call_command('loaddata', file_name)
models.get_model = original_get_model
Вы называете это с load_fixture('my_fixture.json', orm)
изнутри вас направляет определение.
Это было неприятной частью использования светильников и для меня. Моим решением было сделать несколько вспомогательных инструментов. Тот, который создает фикстуры путем выборки данных из базы данных и включает в себя историю миграции на юг в фикстурах.
Существует также инструмент для добавления истории миграции на юг к существующим приборам.
Третий инструмент проверяет коммит, когда этот прибор был изменен, загружает прибор, затем проверяет самый последний коммит и выполняет миграцию на юг и выдает перенесенную базу данных обратно в прибор. Это делается в отдельной базе данных, поэтому ваша база данных по умолчанию не будет перегружена.
Первые два можно считать бета-кодом, а третий, пожалуйста, рассматривайте как пригодную для использования альфу, но они уже весьма полезны для меня.
Хотелось бы получить отзывы от других: git@github.com:JivanAmara/django_fixture_tools.git В настоящее время он поддерживает только проекты, использующие git в качестве RCS.
Вообще Юг обрабатывает миграции, используя forwards()
а также backwards()
функции. В вашем случае вы должны либо:
- изменить приборы, чтобы они содержали правильные данные, или
- импортировать фикстуру перед миграцией, которая его нарушает (или в рамках той же миграции, но до изменения схемы),
Во втором случае, перед миграцией, добавляя (или, как в вашем случае, удаляя) столбец, вы должны выполнить миграцию, которая будет явно загружать приборы аналогично этому ( документы):
def forwards(self, orm):
from django.core.management import call_command
call_command("loaddata", "create_users.json")
Я считаю, что это самый простой способ выполнить то, что вам нужно. Также убедитесь, что вы не делаете некоторых простых ошибок, таких как попытка импортировать данные с новой структурой перед применением более старых миграций.