Django:字段默认值来自模型实例

26 投票
4 回答
19724 浏览
提问于 2025-04-16 03:19

我该如何让一个字段的默认值从已有的模型对象中获取呢?

我尝试了以下几种方法,但都没有成功:

1)

class ModelA(models.Model):
    fieldA = models.CharField(default=self.get_previous())
    
    def get_previous(self):
        return ModelA.objects.all()[0].fieldA

NameError: name 'self' is not defined

2)

class ModelA(models.Model):
    fieldA = models.CharField(default=ModelA.get_previous())

    @staticmethod
    def get_previous():
        return ModelA.objects.all()[0].fieldA

NameError: name 'ModelA' is not defined

3)

class ModelA(models.Model):
    fieldA = models.CharField(default=get_previous())

def get_previous():
    return ModelA.objects.all()[0].fieldA

NameError: global name 'get_previous' is not defined

4)

def get_previous():
    return ModelA.objects.all()[0].fieldA

class ModelA(models.Model):
    fieldA = models.CharField(default=get_previous())

NameError: global name 'ModelA' is not defined

很明显,为什么第3和第4种方法不行。我能理解为什么第1种方法不行——看起来类的属性不能引用实例的属性(也就是self)。我也能理解为什么第2种方法不行——显然在解释器遍历整个类之前,没有对ModelA的引用。

那么我该怎么做呢?

4 个回答

3

选项 1: 使用模型表单。这是一种基于模型的表单,你可以很方便地用特定实例的值来填充这些表单。这种方法适合你想要在表单中显示给用户的默认值。

选项 2: 重写模型的保存方法,在这里编写检查逻辑——如果字段A是空的,就给它赋一个值。这种方法更适合你想要在数据层面上使用默认值,而不仅仅是在表单中使用(也就是说,适用于你通过其他方式创建的实例)。

3

如果你想要输出默认值,可以像这样重写 __getattr__() 方法:

class ModelA(models.Model):
  # your fields
  def __getattr__(self, name):
    if(name == 'fieldA' and !self.fieldA):
      return self.get_previous()
    else:
      return super(ModelA, self).__getattr__(name)

要保存对象的默认值会稍微复杂一点。我想到的第一个解决方案是 重写 save() 方法(我觉得还有更简单的解决办法)

16

在你的例子中,你需要去掉调用运算符 ()

现在这个语句会在第一次读取和解析时立即执行。如果你只写符号名称,Django 类就会得到一个函数指针,它会在真正需要默认值的时候去执行这个函数。

这样例子就变成了:

def get_previous():
    return ModelA.objects.all()[0].fieldA

class ModelA(models.Model):
    fieldA = models.CharField(default=get_previous)

如果你要对很多字段都这样做,建议你重写 save 函数,这样你只需要从数据库中获取一次之前的对象。

撰写回答