如何将含方法调用的计算属性转为Django 5生成字段?
Django 5 GeneratedField 转换Python计算属性的正确写法
问题场景
原有Product模型包含两个Python计算属性price_in_cents和has_expired,尝试转为Django 5的GeneratedField时,price_in_cents报错TypeError: type CombinedExpression doesn't define __round__ method,has_expired也无法直接转换。
1. 转换price_in_cents为GeneratedField
Python内置的round()函数无法直接作用于Django的F()表达式,必须使用Django提供的数据库函数Round实现数据库层面的四舍五入计算。
修改后的字段代码:
from django.db.models import Round price_in_cents = models.GeneratedField( expression=Round(F("price") * 100), output_field=models.BigIntegerField(), db_persist=True, )
2. 转换has_expired为GeneratedField
原逻辑是:若expiry_date不为空,判断当前日期是否晚于expiry_date的日期部分;否则返回False。需用Django的条件表达式Case/When结合日期处理函数实现。
修改后的字段代码:
from django.db.models import Case, When, Value, TruncDate, CurrentDate has_expired = models.GeneratedField( expression=Case( When(expiry_date__isnull=False, then=TruncDate(F("expiry_date")) < CurrentDate()), default=Value(False), output_field=models.BooleanField(), ), db_persist=True, )
完整模型代码
from django.db import models from django.db.models import MinValueValidator from django.db.models import Round, Case, When, Value, TruncDate, CurrentDate class Product(models.Model): price = models.DecimalField( max_digits=19, decimal_places=4, validators=[MinValueValidator(0)], blank=False, null=False, ) price_in_cents = models.GeneratedField( expression=Round(F("price") * 100), output_field=models.BigIntegerField(), db_persist=True, ) expiry_date = models.DateTimeField( blank=True, null=True, ) has_expired = models.GeneratedField( expression=Case( When(expiry_date__isnull=False, then=TruncDate(F("expiry_date")) < CurrentDate()), default=Value(False), output_field=models.BooleanField(), ), db_persist=True, )
内容的提问来源于stack exchange,提问作者darkhorse
相关产品推荐
相关产品推荐

