代码之家  ›  专栏  ›  技术社区  ›  Brian H.

为什么Django迁移在每一行上都使用相同的随机默认值?

  •  1
  • Brian H.  · 技术社区  · 7 年前

    注:

    我理解并非常清楚将函数作为参数传递与调用函数并将结果作为参数传递之间的区别。我相信我传递的函数是正确的。

    规格

    • 德扬戈1.11


    脚本:

    我有几十个模型在我的应用程序中,与许多现有的记录。我需要向这些模型中的每一个添加一个随机种子,这些种子将在创建新模型实例时被创建和设置。我还想为现有实例生成随机种子。

    我的理解是 Django model defaults Migrations 工作是,当一个新字段被添加到模型中时,如果该字段设置了默认值,Djano将用新字段和相应的默认值更新所有现有实例。

    例子

    我的代码的缩短版本:

    def get_random():
        return str(random.random())
    
    class Response(models.Model):
        # various properties
        random = models.CharField(max_length=40, default=get_random)
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        content = JSONField(null=True)
    

    makemigrations 命令生成正确的迁移文件,其中 migrations.AddField() default=get_random 作为参数。

    生成迁移 ,所有现有 Response 实例中包含完全相同的数字 随机的 现场。创建和保存模型的新实例按预期工作(使用伪唯一随机数)。

    变通办法

    一个简单的解决方法是只运行一个执行

    for r in Response.objects.all():
        r.random = get_random()
        r.save()
    

    save() 方法,然后进行大规模保存。但我不认为这些解决办法是必要的。这也意味着,如果我想创建一个具有随机默认值的唯一字段,那么我将需要多次迁移。首先,我必须添加具有指定默认值的字段。接下来,我需要应用迁移并手动重新初始化字段值。然后进行第二次迁移以添加 unique=True


    看起来,如果Django要在 然后它应该使用与创建新实例相同的语义来应用它们。迁移时有没有办法强迫Django为每个模型实例调用函数?

    1 回复  |  直到 7 年前
        1
  •  5
  •   knbk    7 年前

    要将非空列添加到现有表中,Django需要使用 ALTER TABLE ADD COLUMN ... DEFAULT <default_value> . 这只允许Django调用默认函数一次,这就是为什么您看到每一行都有相同的值。

    您的解决方法非常到位,只是您可以使用数据迁移使用唯一值填充现有行,这样就不需要任何手动步骤。本用例的整个过程在文档中描述: https://docs.djangoproject.com/en/2.1/howto/writing-migrations/#migrations-that-add-unique-fields