使用classmethod在Django中设置字段默认值

7 投票
2 回答
3053 浏览
提问于 2025-04-19 09:15

我在网上找到了很多关于这个话题的帖子,但没有人明确指出问题出在哪里。

代码

class Item(models.Model):
    @classmethod
    def get_next_item_number(cls):
        return cls.objects.count() + 1

    number = models.IntegerField(default=get_next_item_number)

问题

当我访问Django的管理面板时,和“数字”字段相关的文本框里显示了

<classmethod object at 0x7fab049d7c50>

所以我尝试修改上面的代码

class Item(models.Model):
    @classmethod
    def get_next_item_number(cls):
        return cls.objects.count() + 1

    number = models.IntegerField(default=get_next_item_number())

但是当我运行Django服务器时,我得到了:

number = models.IntegerField(default=get_next_item_number())
TypeError: 'classmethod' object is not callable

我知道通过把get_next_item_number()声明为一个外部函数可以避免这些问题,但对我来说这个解决方案不太优雅,因为get_next_item_number()只和Item类有关。

我是不是漏掉了什么解决方案?

2 个回答

0

重写你的 __init__ 方法,在这里给你的 Item 类设置默认值,看看下面的代码:

from django.db import models
class Item(models.Model):
    number = models.IntegerField()
    @classmethod
    def get_next_item_number(cls):
        return cls.objects.count() + 1
    def __init__(self, *args, **kwargs):
        super(Item, self).__init__(*args, **kwargs)
        if not self.pk and not self.number:
            self.number = Item.get_next_item_number()

下面是运行结果的流程

>>> from your_app import models
>>> models.Item().save()
>>> models.Item().number
>>> 2
>>> models.Item().save()
>>> models.Item().number
>>> 3
>>> models.Item.objects.filter(id=1)[0].number #number only get its value from classmethod on new items
>>> 1
6

我找到了解决办法:

代码

class Item(models.Model):
    @staticmethod
    def get_next_item_number():
        return Item.objects.count() + 1

    number = models.IntegerField(default=get_next_item_number.__func__)

我对可能的后果不是很了解,但这个方法确实有效。

撰写回答