Django中如何让Product实例的price字段动态返回折扣价?
实现方案
方案一:使用@property装饰器(推荐)
直接在Product模型中添加@property装饰的price方法,覆盖原有字段的访问逻辑,调用product.price时会自动根据is_discount返回对应值:
# models.py from django.db import models class Product(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) discount = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) is_discount = models.BooleanField(default=False) @property def price(self): # 直接获取原始price字段值,避免递归调用 original_price = object.__getattribute__(self, 'price') return self.discount if self.is_discount else original_price
优点:
- 写法简洁直观,符合Python属性访问习惯
- 无需修改现有数据库字段,不影响已有数据
- 视图中无需额外判断,直接调用
product.price即可
优化版(适合新开发项目)
如果允许调整字段命名,可将字段名改为更清晰的命名,避免混淆:
class Product(models.Model): regular_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) discount_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) use_discount = models.BooleanField(default=False) @property def price(self): return self.discount_price if self.use_discount else self.regular_price
方案二:重写__getattribute__方法
通过重写模型的__getattribute__方法拦截属性访问,完全保留原有字段名:
# models.py from django.db import models class Product(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) discount = models.DecimalField(max_digits=10, decimal_places=2, blank=True, default=0.00) is_discount = models.BooleanField(default=False) def __getattribute__(self, name): if name == 'price': # 获取is_discount的值,避免递归调用 is_discount = object.__getattribute__(self, 'is_discount') if is_discount: return object.__getattribute__(self, 'discount') return object.__getattribute__(self, name)
优点:
- 完全保留原有字段名,视图调用逻辑不变
缺点:
__getattribute__会拦截所有属性访问,逻辑复杂时易出问题,调试难度高- 必须使用
object.__getattribute__获取原始属性值,避免递归调用
视图调用示例
无论采用哪种方案,视图中都可以直接调用product.price获取对应价格:
# views.py def page(request): product = Product.objects.get(pk=1) current_price = product.price # 自动返回折扣价或原价
内容的提问来源于stack exchange,提问作者Vitalii Lastname
相关产品推荐
相关产品推荐

