获取模型的历史版本

luf*_*fte 5 django django-models django-migrations

我正在使用Django 1.10,我有两个这样的模型:

class Model1:
    name = models.CharField()

class Model2:
    model1 = models.ForeignKey(Model1, default=get_default_model1)
Run Code Online (Sandbox Code Playgroud)

get_default_model1函数必须获取特定实例Model1(例如,具有特定名称),或者如果它不存在则创建它.问题是这个函数导入Model1并且也将用于迁移:这意味着这样的迁移可能会在Model1修改时中断,因为它将导入新版本Model1而不是当时需要的版本(请参阅此处以获得更好的解释这个问题).

RunPython在迁移中执行操作时,您可以通过apps参数访问模型的历史版本,但情况并非如此.

我编写了以下代码来手动创建我的模型的历史版本:

from django.db import models, connection
from django.db.migrations.loader import MigrationLoader

def get_default_model1():
    loader = MigrationLoader(connection)
    apps = loader.project_state(list(loader.applied_migrations)).apps
    Model1 = apps.get_model('app', 'Model1')
    return Model1.objects.get_or_create(
        name=settings.DEFAULT_NAME,
        defaults={'name': settings.DEFAULT_NAME}
    )[0].pk
Run Code Online (Sandbox Code Playgroud)

但是在一些迁移中,它失败了django.db.migrations.exceptions.NodeNotFoundError: Node ('default', '0004_auto_20160423_0400') not a valid node.它似乎与替换第三方依赖的迁移有关.

有没有更好的方法来获得我的模型的历史版本或完成我在这里尝试做的事情?

Dom*_*kuš 0

您可以将get_default_model1函数定义为:

def get_default_model1(Model1):
    default_model = Model1.objects.get(...)

   return lambda: default_model


class Model1:
    name = models.CharField()


class Model2:
    model1 = models.ForeignKey(Model1, default=get_default_model1(Model1))
Run Code Online (Sandbox Code Playgroud)

然后在迁移中使用它:

Model1 = apps.get_model("<your_app>", "Model1")
Model2 = apps.get_model("<your_app>", "Model2")

for model2 in Model2.objects.all():
    if not model2.model1:
        model2.model1 = get_default_model1(Model1)
Run Code Online (Sandbox Code Playgroud)

我知道这看起来不是最漂亮的,尤其是您必须手动设置默认值的部分,但是您将正确的模型注入到函数中,因此您的目标达到了。