Перенос данных на юг из родительского класса в подкласс - PullRequest
4 голосов
/ 22 июня 2011

У меня есть устаревшая модель Django, которая немного специфична в своем исполнении для моих вкусов. Я хочу создать более конкретные подклассы этой модели для обработки различных сценариев, но хочу сохранить общий базовый класс для некоторых общих полей и методов. Пример модели выглядит следующим образом:

class SomeOldClass(models.Model):
    sharedField1 = models.CharField('This is a shared field1', max_length=10)
    sharedField2 = models.CharField('This is a shared field2', max_length=10)
    specificField1 = models.CharField('This is a specific field1', max_length=10)

В конечном итоге я пытаюсь выделить подкласс SomeOldClass, который разделяет sharedField1 и sharedField2.

class SomeOldSubclass(SomeOldClass):
    specificField1_new = models.CharField('This is a specific field1', max_length=10)

Обратите внимание на _new, добавленный к specificField1 в SomeOldSubclass из-за ошибок при создании поля с тем же именем, что и у родителя.

Мой план - три южных сценария:

  1. Схема миграции для создания нового таблица app_someoldsubclass
  2. Данные сценарий миграции для копирования значений из app_someoldclass.specificField1 to app_someoldsubclass.specificField1_new
  3. миграция схемы для удаления specificField1 из app_someoldclass и переименуйте specificField1_new в specificField1 в app_someoldsubclass

Конечно, я мог бы объединить эти сценарии в один сценарий миграции, но потерпите меня.

Используя классы, определенные выше, я создал скрипт миграции схемы: ./manage.py schemamigration app --auto

Затем я создал сценарий переноса данных empy: ./manage.py datamigration app copy_values

Я изменил скрипт переноса данных, добавив его в свой метод пересылки:

def forwards(self, orm):
    "Write your forwards methods here."
    for soc in orm.SomeOldClass.objects.all():
        sosc = orm.SomeOldSubclass.objects.get_or_create(someoldclass_ptr=soc, specificField_new=soc.specificField1)

Обратите внимание: поскольку SomeOldSubclass наследуется от SomeOldClass, я создаю новый экземпляр SomeOldSubclass для каждого экземпляра SomeOldClass и обновляю значения someoldclass_ptr и specificField1_new.

Запуск миграций создает новую строку в app_someoldsubclass для каждой строки в app_someoldclass, как и ожидалось, со значением specificField1_new, равным значению в app_someoldclass.specificField1. Но теперь все поля в app_someoldclass полностью уничтожены. Если бы я создал экземпляр модели SomeOldClass для существующего идентификатора, sharedField1 было бы None. Фактически, единственное значение, которое все еще допустимо, - это идентификатор в app_someoldclass.

Фактически, единственный способ для app_someoldclass сохранить свои исходные значения - это изменить мой метод forward следующим образом:

def forwards(self, orm):
    "Write your forwards methods here."
    for soc in orm.SomeOldClass.objects.all():
        sosc = orm.SomeOldSubclass.objects.get_or_create(someoldclass_ptr=soc, specificField_new=soc.specificField1)
        soc.save()

(обратите внимание на добавление soc.save () )

Это ожидаемое поведение? Я бы предположил, что, поскольку я не изменяю свои экземпляры SomeOldClass, представленные объектом soc, не было бы необходимости сохранять его снова. И даже если бы я не сохранил его, я бы точно не ожидал, что данные будут засорены.

Это юг? Джанго вещь? Ошибка пользователя?

Ответы [ 2 ]

0 голосов
/ 05 марта 2012

Проблема не в юге, а в использовании подклассов

Когда вы сохраняете подкласс, он устанавливает все значения в базе данных из своих полей. Ваш объект sosc был создан со всеми его родительскими производными полями со значениями по умолчанию.

Когда вы сохраняете подкласс, он перезаписывает родительский. Затем soc.save () снова сбрасывает родителя к его исходным значениям.

См. https://code.djangoproject.com/ticket/7623

0 голосов
/ 07 января 2012

Проблема в get_or_create.Он работает не так, как вы ожидаете.

Есть два способа решить эту проблему:

  • не использовать get_or_create или
  • отладить проблему

Для устранения проблемы вам необходимо:

  • прочитать документацию get_or_create
  • возможно прочитать реализацию get_or_create
  • посмотреть на созданные операторы SQL
...