Миграции Django RunPython не может вызвать методы модели

Я создаю перенос данных с помощью метода RunPython. Однако, когда я пытаюсь запустить метод на объекте, не определены. Можно ли вызвать метод, определенный на модели, используя RunPython?

Ответы

Ответ 1

Методы модели недоступны при миграции, включая миграцию данных.

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

Если у вас был этот метод:

class Order(models.Model):
    '''
    order model def goes here
    '''

    def get_foo_as_bar(self):
        new_attr = 'bar: %s' % self.foo
        return new_attr

Вы можете написать функцию внутри миграции script, например:

def get_foo_as_bar(obj):
    new_attr = 'bar: %s' % obj.foo
    return new_attr


def save_foo_as_bar(apps, schema_editor):
    old_model = apps.get_model("order", "Order")

    for obj in old_model.objects.all():
        obj.new_bar_field = get_foo_as_bar(obj)
        obj.save()

Затем используйте его при переносе:

class Migration(migrations.Migration):

    dependencies = [
        ('order', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(save_foo_as_bar)
    ]

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

Ответ 2

Вы назвали свою модель, как сказано в документации?

def combine_names(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Person = apps.get_model("yourappname", "Person")
    for person in Person.objects.all():
        person.name = "%s %s" % (person.first_name, person.last_name)
        person.save()

Data-Migration Поскольку на данный момент вы не можете импортировать свою модель напрямую:

from yourappname.models import Person

Обновление

Внутренний код Django находится в этом файле django/db/migrations/state.py django.db.migrations.state.ModelState # construct_fields

def construct_fields(self):
    "Deep-clone the fields using deconstruction"
    for name, field in self.fields:
        _, path, args, kwargs = field.deconstruct()
        field_class = import_string(path)
        yield name, field_class(*args, **kwargs)

В экземпляре модели "поддельный" есть только поля, которые являются клонами:

MyModel.__module__ = '__fake__'

Github Django

Ответ 3

Начиная с Django 1.8, вы можете сделать менеджеры моделей доступными для миграций, установив use_in_migrations = True в менеджере моделей. Смотрите документацию по миграции.

Ответ 4

Шрифт наносится на Исторические Модели

Поскольку невозможно сериализовать произвольный код Python, эти исторические модели не будут иметь никаких пользовательских методов, которые вы определили.

Было довольно удивительно, когда я впервые столкнулся с ним во время миграции и не читал мелкий шрифт, потому что он, кажется, противоречит их философии дизайна (добавление функций вокруг моделей)