在 django2 中,如何分别为新对象和遗留对象设置不同的默认值?

In django2 how do I set a different default for new objects and legacy objects respectively?

我想向现有模型添加新字段。出于向后兼容的原因,我想要两个默认值:

我可以看到在迁移中添加字段的代码非常简单:

operations = [
    migrations.AddField(
        model_name='queue',
        name='permission_name',
        field=models.CharField(help_text='Name used in the django.contrib.auth permission system', max_length=50, null=True, verbose_name='Django auth permission name', blank=True),
    ),
]

但是,我看不到应该在何处添加旧版默认值。

PS:说实话,我根本不想要迁移中的遗留默认值。我更希望将它设置在 models.py 中,这样阅读代码的人就可以清楚地知道发生了什么。但我认为它必须在迁移中,我会在 models.py 中发表评论。

似乎没有任何方法可以在 models.py 中指定遗留默认值,但是这可以通过迁移相当容易地完成。

例如,如果您向模型票证添加新迁移 secret_key,您将为这个新字段创建两个迁移。一次迁移将该字段添加为可空字段,随后使用 RunPython 设置旧版默认值。

from django.db import migrations, models
import helpdesk.models

def clear_secret_keys(apps, schema_editor): # set the legacy default
    Ticket = apps.get_model("helpdesk", "Ticket")
    db_alias = schema_editor.connection.alias

    for ticket in Ticket.objects.using(db_alias).all():
         ticket.secret_key='<legacy-default>'
         ticket.save()

class Migration(migrations.Migration):

    dependencies = [
        ('helpdesk', '0017_default_owner_on_delete_null'),
    ]

    operations = [
        migrations.AddField(
            model_name='ticket',
            name='secret_key',
            field=models.CharField(default='<default-for-new-objects>', max_length=36, null=True, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
        ),
        migrations.RunPython(clear_secret_keys),
    ]

如果您不希望您的字段可以为空,则需要创建第二个迁移,将字段更改为不可为空:

from django.db import migrations, models
import helpdesk.models


class Migration(migrations.Migration):

    dependencies = [
        ('helpdesk', '0018_ticket_secret_key'),
    ]

    operations = [
        migrations.AlterField(
            model_name='ticket',
            name='secret_key',
            field=models.CharField(default='<default-for-new-objects>', max_length=36, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
        ),
    ]

写出这个答案时我想到还有另一种方法可以做到这一点,也有两个迁移,那就是首先设置遗留默认值,然后为新对象设置默认值:

from django.db import migrations, models
import helpdesk.models

class Migration(migrations.Migration):

    dependencies = [
        ('helpdesk', '0017_default_owner_on_delete_null'),
    ]

    operations = [
        migrations.AddField(
            model_name='ticket',
            name='secret_key',
            field=models.CharField(default='<legacy-default>', max_length=36, null=True, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
        ),
    ]

如果您不希望您的字段可以为空,则需要创建第二个迁移,将字段更改为不可为空:

from django.db import migrations, models
import helpdesk.models


class Migration(migrations.Migration):

    dependencies = [
        ('helpdesk', '0018_ticket_secret_key'),
    ]

    operations = [
        migrations.AlterField(
            model_name='ticket',
            name='secret_key',
            field=models.CharField(default=helpdesk.models.mk_secret, max_length=36, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
        ),
    ]

这两种方法都应该适用于动态默认值。例如,在这种情况下,新对象的默认值是一个名为 helpdesk.models.mk_secret 的方法,它为所有新创建的对象生成一个唯一的 uuid。