DJANGO非空字段迁移问题

lnxxn5zx  于 2023-06-25  发布在  Go
关注(0)|答案(2)|浏览(125)

我是一个Django/python新手。我添加了两个字段,以便企业和Django管理员的更改记录为谁更新了它们以及更新日期。
约束是这些字段不能为空
我的修改如下:

class Enterprise(models.Model):
    last_updated = models.DateTimeField(
        null=False,
        auto_now=True,
        verbose_name='Last Updated Date',
        help_text="Points to time this was last modified",
    )

    last_updated_by = models.CharField(
        null=False,
        max_length=100,
        default='N/A',
    )

class EnterpriseAdmin(admin.ModelAdmin):
    model = Enterprise

    readonly_fields = (
        "last_updated",
        "last_updated_by",)

    fieldsets = ('last_updated','last_updated_by',),

但是当我运行pytest时,我收到一个错误:* 列“last_updated”中的空值违反了非空约束 *。
当我运行makemigrations时,Django提示我为last_updated添加一个默认值:
You are trying to add a non-nullable field 'last_updated' to enterprise without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows)
所以我选择了选项'1',default=datetime.datetime(1970, 1, 1, 0, 0),preserve_default=False,被添加到我的迁移文件中的last_updated。

migrations.AddField(
            model_name='enterprise',
            name='last_updated',
            field=models.DateTimeField(auto_now=True, default=datetime.datetime(1970, 1, 1, 0, 0), help_text='Points to time this was last modified', verbose_name='Last Updated Date'),
            preserve_default=False,
        ),

我的印象是Unix epoch将作为默认值添加到所有现有列中。

fdbelqdn

fdbelqdn1#

我的印象是Unix epoch将作为默认值添加到所有现有列中。
我在django-4.2上测试了这个,它确实如此,当然可能是这样的,对于一些(非常)旧的版本来说,情况并非如此。
然后,您需要自己提供一个默认值,幸运的是,您可以使用timezone.now
实际上,您可以使用以下命令指定当前日期时间:

It is impossible to add a non-nullable field 'last_updated' to enterprise without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit and manually define a default value in models.py.
Select an option: 1
Please enter the default value as valid Python.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
>>> timezone.now

这将在迁移运行时将该字段设置为时间戳。话虽如此,这可能很奇怪,因为这不是记录最后一次被修改的时间,所以也许null=True是一个更合理的决定。

e4yzc0pl

e4yzc0pl2#

当添加一个新的字段到一个已有表的模型中时,Django需要一个值来用于所有已经存在的行。
如果该字段指定了一个default,那么每个人都很高兴,因为这很好,很简单。
如果字段是可空的并且没有默认值,Django会将现有行的列设置为空。这显然不适用于非空字段。
如果没有这两种解决方案,Django会问你它应该做什么。它不会悄悄地在任何字段上设置非空值,因为这可能会产生意外的影响。
也许你已经有一个命令,检查企业,foos和酒吧,每天晚上运行。它使用getattr来确定对象是否具有last_updated属性,并删除20年前或更久以前最后更新的所有条目。在这种情况下,将默认值设置为1970可能会无意中删除数据库的很大一部分。

相关问题