如何在创建之前验证 Django REST 框架中的输入?
How do I validate input in Django REST framework before creation?
我有一个模型,它代表具有“自选价格”模型的购物项目。卖家可以选择允许客户选择低价、中价或高价。因此,我需要验证用户是否为每个购物项目发送了这三个值之间的有效选项。
目前,我的模型是这样的:
class PurchaseItem(models.Model):
"""
PurchaseItem.
"price" should be treated as a suggestion. We allow users to choose their own price, so we need to validate that
what comes here is a valid choice from the Listing. Otherwise, a malicious user might be able to charge whatever
they want. The Listing model has a ListingPrice with a required 'suggested_cost' field and optional low, medium,
high costs.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
item = models.ForeignKey(Listing, on_delete=models.DO_NOTHING)
price = models.DecimalField(max_digits=8, decimal_places=2, blank=False, null=False)
currency = models.CharField(max_length=30, choices=SUPPORTED_CURRENCIES, default='USD')
created_date = models.DateTimeField(auto_now_add=True)
purchased_by = models.ForeignKey(User, on_delete=models.CASCADE)
def clean(self):
listing_price = self.item.price
valid_prices = [listing_price.suggested_cost]
if listing_price.supports_cost_choice is True:
valid_prices = valid_prices + [listing_price.low_cost, listing_price.medium_cost, listing_price.high_cost]
if self.price not in valid_prices:
raise ValidationError("Selected price is not a valid option.")
super(PurchaseItem, self).clean()
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.clean() # <---- Workaround. I'm trying to remove this.
super(PurchaseItem, self).save(force_insert, force_update, using, update_fields)
当直接保存到数据库或通过 Django 管理面板进行交互时,Django 会调用 clean,我会进行验证,如果不是有效价格则抛出错误,一切正常。效果很好。
问题:
我的问题出在 Create ViewSet 中。我调用 POST 端点,我希望它在保存项目时抛出错误,但它会跳过清理阶段。我添加了断点,它从不调用 clean。因此,我添加了一个解决方法来在保存时手动调用清理。
问题:
如何摆脱对 self.clean() 的手动调用?或者如果价格无效,我如何确保视图集抛出错误?目前,序列化程序的 is_valid 正在返回 true,我不确定序列化程序是否有责任在提交时查找有效价格。为什么序列化程序创建无效对象而不是 运行 clean 方法并抛出验证错误?
在您的序列化程序文件中:
class NameOfYOurModelSerializer(serializers.ModelSerializer):
class Meta:
model = PurchaseItem
fields = (
'price',
)
def validate_price(self, valor): # noqa
# Just an example! I do not know the name of the field and other things; but this will work as a validation to your data.
if value > 0:
# Here is another example: only you can add the condition!
return valor
raise serializers.ValidationError('Description of the error!')
我有一个模型,它代表具有“自选价格”模型的购物项目。卖家可以选择允许客户选择低价、中价或高价。因此,我需要验证用户是否为每个购物项目发送了这三个值之间的有效选项。
目前,我的模型是这样的:
class PurchaseItem(models.Model):
"""
PurchaseItem.
"price" should be treated as a suggestion. We allow users to choose their own price, so we need to validate that
what comes here is a valid choice from the Listing. Otherwise, a malicious user might be able to charge whatever
they want. The Listing model has a ListingPrice with a required 'suggested_cost' field and optional low, medium,
high costs.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
item = models.ForeignKey(Listing, on_delete=models.DO_NOTHING)
price = models.DecimalField(max_digits=8, decimal_places=2, blank=False, null=False)
currency = models.CharField(max_length=30, choices=SUPPORTED_CURRENCIES, default='USD')
created_date = models.DateTimeField(auto_now_add=True)
purchased_by = models.ForeignKey(User, on_delete=models.CASCADE)
def clean(self):
listing_price = self.item.price
valid_prices = [listing_price.suggested_cost]
if listing_price.supports_cost_choice is True:
valid_prices = valid_prices + [listing_price.low_cost, listing_price.medium_cost, listing_price.high_cost]
if self.price not in valid_prices:
raise ValidationError("Selected price is not a valid option.")
super(PurchaseItem, self).clean()
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.clean() # <---- Workaround. I'm trying to remove this.
super(PurchaseItem, self).save(force_insert, force_update, using, update_fields)
当直接保存到数据库或通过 Django 管理面板进行交互时,Django 会调用 clean,我会进行验证,如果不是有效价格则抛出错误,一切正常。效果很好。
问题:
我的问题出在 Create ViewSet 中。我调用 POST 端点,我希望它在保存项目时抛出错误,但它会跳过清理阶段。我添加了断点,它从不调用 clean。因此,我添加了一个解决方法来在保存时手动调用清理。
问题:
如何摆脱对 self.clean() 的手动调用?或者如果价格无效,我如何确保视图集抛出错误?目前,序列化程序的 is_valid 正在返回 true,我不确定序列化程序是否有责任在提交时查找有效价格。为什么序列化程序创建无效对象而不是 运行 clean 方法并抛出验证错误?
在您的序列化程序文件中:
class NameOfYOurModelSerializer(serializers.ModelSerializer):
class Meta:
model = PurchaseItem
fields = (
'price',
)
def validate_price(self, valor): # noqa
# Just an example! I do not know the name of the field and other things; but this will work as a validation to your data.
if value > 0:
# Here is another example: only you can add the condition!
return valor
raise serializers.ValidationError('Description of the error!')