Django3.2继承DecimalField自定义字段报混合类型错误如何解决
Django 3.2 调整了组合表达式的类型校验逻辑:ORM层判定表达式类型兼容性时,不再仅参考get_internal_type()返回的数据库层类型,而是通过字段类的_resolve_type方法做Python侧的类型匹配。自定义的DecimalFWB作为DecimalField的子类,默认继承的_resolve_type方法会将自身和父类DecimalField识别为两种不同类型,因此当表达式中同时出现Value包装的Decimal值(自动识别为DecimalField类型)和DecimalFWB类型的字段时,就会抛出混合类型错误。
-F("frac") + Decimal(1)能正常运行,是因为一元运算符-处理F("frac")后,返回的表达式output_field已经被解析为原生DecimalField,后续和Decimal值运算时类型一致,不会触发校验报错。
不需要在每个注解处冗余写ExpressionWrapper,只需要在自定义字段类中重写_resolve_type方法,明确告知Django该字段和所有DecimalField子类类型兼容,类型解析逻辑完全复用原生DecimalField的规则即可:
from django.db.models import DecimalField from django.core.validators import MinValueValidator from decimal import Decimal class DecimalFWB(DecimalField): def _resolve_type(self, other): # 与所有DecimalField体系字段兼容,复用父类解析逻辑 if isinstance(other, DecimalField): return super()._resolve_type(other) return NotImplemented @property def validators(self): return super().validators + [MinValueValidator(0.1), ]
添加上述方法后,无论自定义字段和原生DecimalField(包括自动包装Decimal值生成的Value表达式)在运算中的顺序如何,都不会再触发混合类型报错,封装自定义字段减少重复配置的逻辑可以正常生效。
get_internal_type()方法仅用于控制模型生成数据库表时的列类型映射,不参与ORM层表达式运算的类型校验,因此仅实现该方法无法解决3.2版本后的类型兼容问题。
内容的提问来源于stack exchange,提问作者anx

