如何强制 Django 模型中的 2 个字段共享相同的默认值?

Posted

技术标签:

【中文标题】如何强制 Django 模型中的 2 个字段共享相同的默认值?【英文标题】:How can I force 2 fields in a Django model to share the same default value? 【发布时间】:2016-06-13 04:59:24 【问题描述】:

我有一个 Django 模型MyModel,如下所示。

它有两个 DateTimeField 类型的字段:my_field1my_field2

from django.db import models
from datetime import datetime

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField(
        # WHAT DO I PUT HERE?
    ) 

我希望这两个字段都默认为 datetime.utcnow() 的值。但我想为两者保存相同的值。拨打utcnow() 两次似乎很浪费。

如何设置my_field2 的默认值,以便它简单地复制my_field1 的默认值?

【问题讨论】:

不要对Date/DateTime 字段使用默认值。它被缓存并保持不变,直到 Python 进程没有重新启动。使用auto_nowauto_now_add @Todor 他使用的是default=datetime.utcnow 而不是default=datetime.utcnow()——所以这个值不是“缓存的”,而是每次都计算出来的。 啊,我没注意到。 【参考方案1】:

执行此操作的正确方法是覆盖 save 方法而不是 __init__ 方法。事实上,不建议重写 init 方法,如果你想控制对象的读取方式,更好的方法是重写 from_db 或如果你想控制对象的保存方式,则使用 save 方法。

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField()

    def save(self, *arges, **kwargs):
        if self.my_field1 is None:
            self.my_field1 = datetime.utcnow()
            if self.my_field2 is None:
                self.my_field2 = self.my_field1

        super(MyModel, self).save(*args, **kwargs)

更新:我的声明参考:https://docs.djangoproject.com/en/1.9/ref/models/instances/

您可能想通过覆盖 init 来自定义模型 方法。但是,如果您这样做,请注意不要更改呼叫 签名,因为任何更改都可能阻止模型实例 保存。而不是覆盖 init,尝试使用其中之一 方法:

【讨论】:

> 事实上,不建议覆盖__init__ 方法——你从哪里得到的? 我不会称之为“不推荐”。只是警告要保留签名。【参考方案2】:

如docs中所述:

在创建新模型实例且未为字段提供值时使用默认值。

因此,为了解决您的任务,我将在__init__ 中手动填写默认值。比如:

def __init__(self, *args, **kwargs):
    now = datetime.datetime.utcnow()
    kwargs.setdefault('my_field1', now)
    kwargs.setdefault('my_field2', now)
    super(MyModel, self).__init__(*args, **kwargs)

您也可以处理save 方法中的值。

如果您希望 my_field2 具有 my_field1 中的任何值,我会采用此解决方案:

class MyModel(models.Model):
    my_field1 = models.DateTimeField(default=datetime.utcnow, editable=False)
    my_field2 = models.DateTimeField()

    def __init__(self, **kwargs):
        super(MyModel, self).__init__(**kwargs)
        if self.my_field2 is None:
            self.my_field2 = self.my_field1

【讨论】:

您能否修改您的答案,使my_field2 默认为my_field1 中的任何值?如果提供了my_field1,但没有提供my_field2,则您的解决方案不会将值从一个复制到另一个。 那个构造函数破坏了类。见这里:***.com/questions/37802041/…

以上是关于如何强制 Django 模型中的 2 个字段共享相同的默认值?的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中,为啥模型中的 blank=True 不会使表单字段不是强制性的?

如何在 django 模型字段中强制执行 char(N) 数据类型而不是 varchar(N)

如何在需要的基本 Django 用户模型中获取电子邮件字段?

如何在 Django 中将 2 个模型字段结合在一起?

Django 模板:使用 get_FOO_display() 强制选择字段并打印显示值

django模型,如何动态设置查询的字段?