Django迁移RunPython无法调用模型方法

时间:2015-02-28 02:14:11

标签: django django-models django-migrations

我正在使用RunPython方法创建数据迁移。但是,当我尝试在对象上运行方法时,没有定义。是否可以使用RunPython

调用模型上定义的方法

5 个答案:

答案 0 :(得分:36)

模型方法在迁移中不可用,包括数据迁移。

然而,有一种解决方法,它应该与调用模型方法非常相似。您可以在迁移中定义模拟您要使用的模型方法的函数。

如果你有这个方法:

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

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

您可以在迁移脚本中编写函数,如:

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)
    ]

这种迁移方式可行。将会有一些重复的代码,但这并不重要,因为数据迁移应该是在应用程序的特定状态下的一次操作。

答案 1 :(得分:14)

你是否按照文档中的说法调用了你的模型?

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

答案 2 :(得分:4)

As of Django 1.8, you can make model managers available to migrations by setting use_in_migrations = True on the model manager. See the migrations documentation.

答案 3 :(得分:2)

这不能回答 OP,但可能仍然对某人有用。

不仅自定义模型方法在迁移中不可用,其他模型属性也是如此,例如用于模型字段 choices 的类“常量”。请参阅 docs 中的示例。

在这种特定的边缘情况下,我们无法在迁移过程中直接访问选项的 historical 值,但我们可以从模型字段中获取历史值,使用 {{ 3}},因为这些值包含在迁移中。

鉴于 Django 的 Student model _meta api

class Student(models.Model):
    FRESHMAN = 'FR'
    ...
    YEAR_IN_SCHOOL_CHOICES = [(FRESHMAN, 'Freshman'), ...]
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

我们可以按如下方式获取迁移中 Student.FRESHMAN 的历史值:

...
Student = apps.get_model('my_app', 'Student')
YEAR_IN_SCHOOL_CHOICES = Student._meta.get_field('year_in_school').choices
...

答案 4 :(得分:0)

精美图片位于Historical Models

  

由于无法序列化任意Python代码,因此这些历史模型将没有您定义的任何自定义方法。

当我在迁移过程中第一次遇到它并且没有阅读精美的印刷版时感到非常惊讶,因为这似乎与他们的Design Philosophy(在模型周围添加功能)相矛盾