Django模型继承层次结构中字段的基于类的默认值

时间:2010-09-24 12:20:02

标签: django dynamic model default field

如何在以下方案中完成基于类的默认值?我的意思是,我想继承类为“数字”设置默认值的方式不同:

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField(default=self.create_number())

    @classmethod
    def create_number(cls):
        raise NotImplementedError

class Invoice(OrderDocumentBase):
    @classmethod
    def create_number(cls):
        return 1

class CreditAdvice(OrderDocumentBase):
    @classmethod
    def create_number(cls):
        return 2

我查看了this stackoverflow question,但它没有解决同样的问题。我认为唯一有用的就是重载OrderDocumentBase __init__这样的方法:

def __init__(self, *args, **kwargs):
    """
    Overload __init__ to enable dynamic set of default to number
    """
    super(OrderDocumentBase, self).__init__(*args, **kwargs)
    number_field = filter(lambda x: x.name == 'number', self._meta.fields)[0]
    number = self.__class__.create_number()
    number_field.default = number

这是有效的,但只是部分和行为非常奇怪。在管理界面中,我可以看到仅在第二页或后一页刷新后才设置默认值。首次尝试时,None正在设置:(

第二种可能性是重新定义每个类中的数字字段,但这看起来并不太漂亮。还有其他办法吗?

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:5)

通过默认=这样做确实感觉更好,但是你在那里使用的任何东西都没有办法进入你的班级或特定的模型。要让它在管理员等地方正确显示,您可以在 init ()而不是save()中进行设置。

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField()

    def __init__(self, *args, **kwargs):
        super(OrderDocumentBase, self).__init__(*args, **kwargs)
        if not self.pk and not self.number:
            self.number = self.DEFAULT_NUMBER

class Invoice(OrderDocumentBase):
    DEFAULT_NUMBER = 2

class CreditAdvice(OrderDocumentBase):
    DEFAULT_NUMBER = 3

答案 1 :(得分:2)

这里有几个问题。首先,self.method不起作用。在类的主体的上下文中没有self,这是您声明PositiveIntegerField的位置。

其次,传递一个callable将不起作用,因为callable在编译时被绑定并且在运行时不会更改。所以如果你定义说,

class OrderDocumentBase(PdfPrintable):
    create_number = lambda: return 0
    number = models.PositiveIntegerField(default=create_number)

class Invoice(OrderDocumentBase):
    create_number = lambda: return 1

所有Invoice个实例仍会以0作为默认值。

我能想到解决这个问题的一种方法是覆盖save()方法。您可以检查是否未提供number并在保存之前将其设置为默认值。

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField()

    def save(self, *args, **kwargs):
        if not self.number:
            self.number = self.DEFAULT
        super(OrderDocumentBase, self).save(*args, **kwargs)

class Invoice(OrderDocumentBase):
    DEFAULT = 2

class CreditAdvice(OrderDocumentBase):
    DEFAULT = 3

我测试了上面的一个小改动(由于我没有OrderDocumentBase而得到PdfPrintable摘要)并且它按预期工作。