Использование Django South для перехода от конкретного наследования к абстрактному наследованию - PullRequest
10 голосов
/ 18 августа 2011

У меня есть существующий проект 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.

Итак, во-первых,это будет работать?И второе: есть ли лучший способ сделать это?

Обновление:

Мое окончательное решение подробно описано здесь:

http://www.markliu.me/2011/aug/23/migrating-a-django-postgres-db-from-concrete-inhe/

Ответы [ 2 ]

7 голосов
/ 21 августа 2011
  1. Добавьте NewBaseModel, мы используем другое имя, чтобы оно не конфликтовало с текущим неабстрактным (в противном случае Юг фактически удалит BaseModel).

    class NewBaseModel(models.Model):
        user = models.ForeignKey(User)
        another_field = models.CharField(max_length=1000)
    
        class Meta:
            abstract = True
    
  2. Установите Model1 и Model2 для наследования от NewBaseModel

  3. Запустить schemamigration --auto, 2 новых поля будут добавлены в Model1 и Model2
  4. Запустите datamigration --empty и заполните новые поля из значений в BaseModel
  5. Загрузите производственную базу данных и дважды проверьте правильность переноса
  6. Удалить BaseModel и переименовать NewBaseModel в BaseModel
  7. Запустить schemamigration --auto (это должно работать;))
  8. Развертывание!

ПРИМЕЧАНИЕ. Используйте переменную orm при миграции для использования текущего состояния схемы модели.

1 голос
/ 21 августа 2011

Ответ Себастьяна Трепча, вероятно, хороший, но еще один способ сделать это - создать миграцию вручную:

  1. Добавьте abstract = True к базовой модели.

  2. Запустите schemamigration --auto, сгенерированная миграция, вероятно, не будет хорошей, но вы будете использовать ее в качестве базы.

  3. Редактировать файл миграции. В forward вы должны добавить, в следующем порядке:

    а. db.delete_foreign_key(table_name, column) для каждой модели ваших детей. Это удалит ForeignKey между родительской и дочерней таблицами.

    б. db.delete_table(BaseModel) удалить таблицу базовой модели (эта команда, вероятно, должна быть уже там, сгенерирована --auto).

    с. Возможно, вам придется переименовать все столбцы первичных ключей ваших дочерних моделей в «id». Я не уверен в этом. Если вам нужно сделать это: db.rename_column(table_name, column_name, 'id') для каждой из моделей ваших детей.

  4. Удалите весь автоматически сгенерированный код в forward, который не имеет смысла.

  5. Запустить миграцию: migrate

Этот метод выполняет удаление таблицы базового класса и внешних ключей между таблицей базового класса и ее дочерними элементами, поскольку они не используются с абстрактным базовым классом.

Я не тестировал этот метод, поэтому возможно, что вы столкнетесь с некоторыми проблемами. Этот подход более сложен, чем другой, но его преимущества в том, что вам не нужно переносить данные и вы поймете, что происходит. Он также должен работать довольно быстро, что хорошо для живой миграции.

Для получения дополнительной информации вы можете обратиться к South API .

Одна очень важная вещь: при любом методе, который вы будете использовать, работайте с локальной копией вашей системы и базы данных. Когда вы по-настоящему убедитесь, что миграция работает хорошо, создайте резервную копию рабочей БД, затем примените миграцию и перезапустите веб-сервер (чтобы загрузить измененный код модели).

...