在Django-money的MoneyField中能否为Min/MaxMoneyValidator设置带小数数值?
关于Django-money中MinMoneyValidator/MaxMoneyValidator传入小数的问题
问题场景
使用Django-money的MoneyField时,为MinMoneyValidator传入0.00、MaxMoneyValidator传入999.99,代码如下:
# "models.py" from django.db import models from djmoney.models.fields import MoneyField from djmoney.models.validators import MinMoneyValidator, MaxMoneyValidator class Product(models.Model): name = models.CharField(max_length=50) price = MoneyField( max_digits=5, decimal_places=2, default=0, default_currency='USD', validators=[ MinMoneyValidator(0.00), MaxMoneyValidator(999.99), ] )
添加商品时触发错误:
TypeError: 'float' object is not subscriptable
改为传入整数0和999后错误消失,但Django原生DecimalField中给MinValueValidator/MaxValueValidator传入0.00、999.99完全正常:
# "models.py" from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator class Product(models.Model): name = models.CharField(max_length=50) price = models.DecimalField( max_digits=5, decimal_places=2, default=0, validators=[ MinValueValidator(0.00), MaxValueValidator(999.99) ], )
错误原因
Django-money的MinMoneyValidator/MaxMoneyValidator内部逻辑会尝试对传入的验证值做类序列的下标操作(比如提取金额部分),但直接传入float类型的数值时,float对象不支持下标访问,因此抛出TypeError。
而Django原生的数值验证器是直接处理数值类型,对float有兼容逻辑,所以不会触发错误。
正确设置带小数的验证值
并非不能设置带小数的验证值,而是需要传入Decimal类型或者Django-money的Money对象,而非float:
方法1:使用Decimal类型
# "models.py" from django.db import models from decimal import Decimal from djmoney.models.fields import MoneyField from djmoney.models.validators import MinMoneyValidator, MaxMoneyValidator class Product(models.Model): name = models.CharField(max_length=50) price = MoneyField( max_digits=5, decimal_places=2, default=0, default_currency='USD', validators=[ MinMoneyValidator(Decimal('0.00')), MaxMoneyValidator(Decimal('999.99')), ] )
方法2:使用Money对象
# "models.py" from django.db import models from djmoney.models.fields import MoneyField from djmoney.money import Money from djmoney.models.validators import MinMoneyValidator, MaxMoneyValidator class Product(models.Model): name = models.CharField(max_length=50) price = MoneyField( max_digits=5, decimal_places=2, default=0, default_currency='USD', validators=[ MinMoneyValidator(Money(0.00, 'USD')), MaxMoneyValidator(Money(999.99, 'USD')), ] )
内容的提问来源于stack exchange,提问作者Super Kai - Kazuya Ito
相关产品推荐
相关产品推荐

