【问题标题】:Django Migrations Add Field with Default as Function of ModelDjango Migrations 添加默认字段作为模型的功能
【发布时间】:2015-06-29 12:54:18
【问题描述】:

我向我的 Django 模型添加了一个新的、不可为空的字段,并尝试使用迁移来部署该更改。我如何将现有模型的默认值设置为这些模型的某个函数而不是常量?

例如,假设我之前有一个 created_on 字段,我刚刚添加了一个 updated_on 字段,我想将其值初始设置为模型的 created_on。我将如何在迁移中执行此操作?

这就是我想要开始的:

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(default=????, auto_now=True),
        preserve_default=False,
    ),

【问题讨论】:

    标签: django django-models django-migrations


    【解决方案1】:

    我刚刚学会了如何通过一次迁移来做到这一点!

    当运行makemigrations django 时应该要求你设置一个一次性的默认值。在这里定义任何你可以让它快乐的东西,你最终会得到你提到的迁移AddField

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(default=????, auto_now=True),
        preserve_default=False,
    ),
    

    把这1个操作改成3个操作:

    1. 最初使该字段可以为空,因此将添加该列。
    2. 调用函数以根据需要填充字段。
    3. 更改字段(使用AlterField)使其不可为空(如上,无默认值)。

    所以你最终会得到这样的结果:

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(null=True, auto_now=True),
    ),
    migrations.RunPython(set_my_defaults, reverse_func),
    migrations.AlterField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(auto_now=True),
    ),
    

    将您的函数定义为:

    def set_my_defaults(apps, schema_editor):
        Series = apps.get_model('myapp', 'Series')
        for series in Series.objects.all().iterator():
            series.updated_as = datetime.now() + timedelta(days=series.some_other_field)
            series.save()
    
    def reverse_func(apps, schema_editor):
        pass  # code for reverting migration, if any
    

    除了,你知道,并不可怕。

    注意:考虑使用F expressions 和/或database functions 来提高大型数据库的迁移性能。

    【讨论】:

    • 您可以使用:Series.objects.all().update(updated_as=datetime.now() + timedelta(days=series.some_other_field)) #update 作为单个请求工作
    • 您应该使用migrations.RunPython.noop,而不是reverse_func。查看文档以获取更多详细信息 - docs.djangoproject.com/en/2.1/ref/migration-operations/…
    • 在提示要求默认值的情况下,是否可以从函数中获取类似的动态值?提示确实提到 > Please enter the default value now, as valid Python
    • @Fusion 或者如果您不希望迁移是可逆的,您可以省略第二个参数docs.djangoproject.com/en/2.2/howto/writing-migrations/#id6
    【解决方案2】:

    您需要在两次迁移中执行此操作。首先,添加您的字段,但可以为空。像往常一样创建一个迁移文件。之后将您的字段设置为不可为空并再次运行 makemigrations,但不要启动迁移。打开第二个迁移并在顶部定义一个函数:

    def set_field_values(apps, schema_editor):
        # use apps.get_model("app_name", "model_name") and set the defualt values
    

    然后,在您的迁移文件中有一个操作列表。 之前修改字段操作添加

    RunPython(set_field_values)
    

    它应该这样做

    【讨论】:

      【解决方案3】:

      您还应该为您的函数 set_my_defaults() 定义一个反向,以防您将来要恢复迁移。

      def reverse_set_default(apps, schema_editor):
          pass
      

      在这种情况下,reverse 函数不需要执行任何操作,因为您正在删除该字段。

      并将其添加到 RunPython:

      migrations.RunPython(set_my_defaults, reverse_set_default),
      

      【讨论】:

      • 您应该将此作为评论发布到@FraggaMuffin 的答案。
      • 如果你只是使用pass的函数,你应该使用migrations.RunPython.noop。所以migrations.RunPython(set_my_defaults, migrations.RunPython.noop)
      猜你喜欢
      • 2011-06-04
      • 2017-11-10
      • 1970-01-01
      • 2018-10-21
      • 2010-10-19
      • 2014-12-07
      • 1970-01-01
      相关资源
      最近更新 更多