Использование Django South для перехода от конкретного наследования к абстрактному наследованию
У меня есть существующий проект Django, который имеет несколько моделей, использующих конкретное наследование базового класса. После более пристального рассмотрения и после прочтения о том, что люди, подобные Якобу Каплану-Мосу должны сказать об этом, использование этого конкретного наследования в моем случае не нужно. Я хотел бы перейти на использование абстрактного базового класса.
Дело в том, что этот сложный процесс заключается в том, что мой сайт активен, и я ввел данные пользователя. Таким образом, мне нужно сохранить все мои данные в течение всего этого перехода.
Я приведу пример, чтобы быть более конкретным:
До:
app1/models.py:
class Model1(base_app.models.BaseModel):
field1 = models.CharField(max_length=1000)
field2 = models.CharField(max_length=1000)
app2/models.py:
class Model2(base_app.models.BaseModel):
field1 = models.CharField(max_length=1000)
field2 = models.CharField(max_length=1000)
base_app/models.py:
class BaseModel(models.Model):
user = models.ForeignKey(User)
another_field = models.CharField(max_length=1000)
После
app1/models.py:
class Model1(base_app.models.BaseModel):
field1 = models.CharField(max_length=1000)
field2 = models.CharField(max_length=1000)
app2/models.py:
class Model2(base_app.models.BaseModel):
field1 = models.CharField(max_length=1000)
field2 = models.CharField(max_length=1000)
base_app/models.py:
class BaseModel(models.Model):
user = models.ForeignKey(User)
another_field = models.CharField(max_length=1000)
class Meta:
abstract = True
Сейчас я планирую сначала добавить abstract = True
в BaseModel. Затем для каждой модели, которая использует BaseModel
, по одному за раз:
- Используйте юг для переноса базы данных и создания этой миграции с помощью флага --auto
- Используйте южную миграцию данных. Например, я прокрутил бы каждый объект в Model1 для извлечения объекта в BaseModel, который имеет тот же pk и скопирует значения для каждого поля объекта BaseModel для объекта Model1.
Итак, во-первых, будет ли это работать? И, во-вторых, есть ли лучший способ сделать это?
Update:
Мое окончательное решение подробно описано здесь:
http://www.markliu.me/2011/aug/23/migrating-a-django-postgres-db-from-concrete-inhe/
Ответы
Ответ 1
-
Добавьте NewBaseModel, мы используем другое имя, чтобы оно не противоречило текущему не абстрактному (в противном случае Юг фактически удалил бы BaseModel).
class NewBaseModel(models.Model):
user = models.ForeignKey(User)
another_field = models.CharField(max_length=1000)
class Meta:
abstract = True
-
Задайте Model1 и Model2 для наследования из NewBaseModel
- Запустить схематизацию --авто, добавлены 2 новых поля в Model1 и Model2
- Запустить datamigration -empty и заполнить новые поля из значений в BaseModel
- Загрузите db и дважды проверьте, все ли выполнено правильно.
- Удалить BaseModel и переименовать NewBaseModel в BaseModel
- Запустить схематизацию --auto (это должно работать;))
- Развертывание!
ПРИМЕЧАНИЕ. При переносе используйте переменную orm, чтобы использовать текущее состояние вашей модели.
Ответ 2
Ответ Sebastjan Trepča, вероятно, хорош, но другой способ сделать это - создать миграцию вручную:
-
Добавьте abstract = True
в базовую модель.
-
Запустите schemamigration --auto
, сгенерированная миграция, вероятно, не будет хорошей, но вы будете использовать ее в качестве базы.
-
Отредактируйте файл миграции. В forward
вы должны добавить в следующем порядке:
а. db.delete_foreign_key(table_name, column)
для каждой из моделей ваших детей. Это приведет к удалению ForeignKey между родительской и дочерней таблицами.
б. db.delete_table(BaseModel)
, чтобы удалить таблицу базовой модели (эта команда должна быть, вероятно, уже создана, сгенерирована --auto).
с. Возможно, вам придется переименовать весь столбец первичного ключа ваших моделей детей в "id". Я не уверен в этом. Если вам нужно сделать это: db.rename_column(table_name, column_name, 'id')
для каждой из моделей ваших детей.
-
Удалите весь автоматически сгенерированный код в forward
, который не имеет смысла.
-
Запустите миграцию: migrate
Что делает этот метод, это удаление таблицы базового класса и внешних ключей между таблицей базового класса и ее дочерними элементами, поскольку они не используются с абстрактным базовым классом.
Я не тестировал этот метод, поэтому вы можете столкнуться с некоторыми проблемами. Этот подход более сложный, чем другой, но преимущества в том, что вам не нужно переносить данные и что вы поймете, что происходит. Он должен работать довольно быстро, это хорошо для живой миграции.
Для получения дополнительной информации вы можете обратиться к South API.
Одна действительно важная вещь в любом методе, который вы будете использовать, работать с локальной копией вашей системы и базы данных. Когда вы действительно убедитесь, что миграция работает хорошо, создайте резервную копию своей производственной базы данных, затем примените перенос, а затем перезапустите веб-сервер (чтобы загрузить измененный код модели).