Django模型中如何实现类似Java静态属性的实例快捷访问?
解决Django PayType模型静态实例获取问题
问题原因
你用@property装饰器定义的CREDIT、DEBIT是实例属性,当直接通过PayType.CREDIT调用时,得到的是property对象本身,而非数据库中的PayType实例,所以外键赋值时会提示类型不匹配。
解决方案
下面几种方法都能实现类似Java静态属性的效果,快速获取固定的PayType实例:
方法1:类属性+缓存(推荐)
在PayType模型中定义类属性,第一次调用时从数据库获取实例并缓存,后续直接复用缓存的实例:
from django.db import models class PayType(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50, unique=True) # 缓存实例的类属性 _CREDIT = None _DEBIT = None _CASH = None @classmethod def CREDIT(cls): if cls._CREDIT is None: # 用get_or_create避免数据缺失报错 cls._CREDIT, _ = cls.objects.get_or_create(name="Credit") return cls._CREDIT @classmethod def DEBIT(cls): if cls._DEBIT is None: cls._DEBIT, _ = cls.objects.get_or_create(name="Debit") return cls._DEBIT @classmethod def CASH(cls): if cls._CASH is None: cls._CASH, _ = cls.objects.get_or_create(name="Cash") return cls._CASH
使用时直接调用类方法:
pay = Pay.objects.create( # 其他字段 pay_type=PayType.CREDIT() )
方法2:类级属性写法(无需括号调用)
如果想实现类似直接属性访问的写法(不带括号),可以用类属性结合classmethod包装:
from django.db import models class PayType(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50, unique=True) @classmethod def _get_credit(cls): obj, _ = cls.objects.get_or_create(name="Credit") return obj @classmethod def _get_debit(cls): obj, _ = cls.objects.get_or_create(name="Debit") return obj @classmethod def _get_cash(cls): obj, _ = cls.objects.get_or_create(name="Cash") return obj # 定义类级属性,直接返回实例 CREDIT = property(classmethod(lambda cls: cls._get_credit())) DEBIT = property(classmethod(lambda cls: cls._get_debit())) CASH = property(classmethod(lambda cls: cls._get_cash()))
使用时直接通过类访问属性:
pay = Pay.objects.create( # 其他字段 pay_type=PayType.CREDIT )
方法3:硬编码ID(不推荐)
如果确定迁移插入的三条数据ID绝对不会变动,可以直接用ID赋值:
class PayType(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50, unique=True) # 假设迁移后三条数据的ID分别是1、2、3 CREDIT_ID = 1 DEBIT_ID = 2 CASH_ID = 3
使用时直接赋值ID:
pay = Pay.objects.create( # 其他字段 pay_type_id=PayType.CREDIT_ID )
这种方法的缺点是一旦数据库重建或ID变更,代码会直接报错,仅适合数据完全固定的场景。
内容的提问来源于stack exchange,提问作者maizorin97
相关产品推荐
相关产品推荐

