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

发布于 2024-09-24 22:28:33 字数 1224 浏览 3 评论 0原文

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

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

我查看了 这个 stackoverflow 问题,但它没有解决同样的问题。我认为唯一可行的是重载 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 被设置:(

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

有人可以帮忙吗?

How can one accomplish class-based default value in following scheme? I mean, I would like to inherited classes set default value for "number" differently:

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

I have looked at this stackoverflow question, but it doesn't address the same problem. The only thing I thought would work was overloading OrderDocumentBase's __init__ method like this:

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

This works, but only partially and behaves quite wierdly. In admin interface, I can see the default being set only after second or latter page refresh. On first try, None is being set :(

Second possibility is redefinition of number field in each class, but that doesn't seem too much pretty. Is there any other way?

Can someone help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橘虞初梦 2024-10-01 22:28:33

通过 default= 执行此操作确实感觉更好,但是您在那里使用的任何内容都无法获取您的类或特定模型。为了让它在管理员等地方正确显示,您可以在 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

It does feel nicer to do this via default=, but anything you use there doesn't have a way to get at your class or specific model. To have it show up properly in places like the admin, you could set it in init() instead of 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
初懵 2024-10-01 22:28:33

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

其次,传递可调用对象将不起作用,因为可调用对象在编译时绑定并且在运行时不会更改。因此,如果您定义,

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),并且它按预期工作。

There are a couple of problems here. First, the self.method is not going to work. There is no self in the context of the body of the class, which is where you are declaring the PositiveIntegerField.

Second, passing a callable will not work as the callable gets bound at compile time and does not change at runtime. So if you define say,

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

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

All Invoice instances will still get 0 as default value.

One way I can think of to tackle this is to override the save() method. You can check if the number has not been supplied and set it to a default before saving.

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

I tested the above with a small change (made OrderDocumentBase abstract as I did not have PdfPrintable) and it worked as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文