【问题标题】:How to skip validation for DRF serializer FloatField如何跳过 DRF 序列化程序 FloatField 的验证
【发布时间】:2019-10-16 15:23:35
【问题描述】:

问题

我需要添加将minimum_commission 保存为正数的功能,但 None 也可用。我已经添加了序列化器:

class Appartement(models.Model):
    minimum_commission = models.FloatField(null=True, default=None)

class RentalTestSerializer(serializers.ModelSerializer):
    minimum_commission = serializers.FloatField(required=False, min_value=0)

    class Meta:
        model = Appartement
        fields = (
            'minimum_commission',
        )

但是当我从表单(或外壳)传递空字符串时,我看到A valid number is required 验证错误。

In [21]: ser = RentalTestSerializer(data={'minimum_commission': ''})

In [22]: ser.is_valid()
Out[22]: False

In [23]: ser.errors
Out[23]:
ReturnDict([('minimum_commission',
             [ErrorDetail(string=u'A valid number is required.', code=u'invalid')])])

可能的解决方案

起初我添加了自定义字段:BlankableFloatField,它将空字符串转换为无:

class BlankableFloatField(serializers.FloatField):
    """
    We wanted to be able to receive an empty string ('') or 'null' for a float field
    and in that case turn it into a None number
    """
    def to_internal_value(self, data):
        if data in ['', 'null']:
            return None

        return super(BlankableFloatField, self).to_internal_value(data)

并添加了自定义验证:

class RentalTestSerializer(serializers.ModelSerializer):
    minimum_commission = BlankableFloatField(required=False)

    class Meta:
        model = Appartement
        fields = (
            'minimum_commission',
        )

    def validate_minimum_commission(self, value):
        if value and value < 0:
            raise serializers.ValidationError(_("Minimum commission should be greater than 0"))
        return value

现在它按预期工作:

In [38]: ser = RentalTestSerializer(data={'minimum_commission': ''})

In [39]: ser.is_valid()
Out[39]: True

但我认为有没有办法让它更优雅?


更新:

正如我所见,主要问题是从表单中传递空字符串。我需要它来重置minimum_commission 列。所以,最终的解决方案是:

class Appartement(models.Model):
    # I have added the blank=True and validator
    minimum_commission = models.FloatField(null=True, default=None, blank=True, validators=[MinValueValidator(0.0)]) 

class RentalTestSerializer(serializers.ModelSerializer):
    # I continue to use the custom field to transform empty space to the None 
    # but instead of custom validation just added the allow_null=True and min_value validator.
    minimum_commission = BlankableFloatField(required=False, allow_null=True, min_value=0)

    class Meta:
        model = Appartement
        fields = (
            'minimum_commission',
        )

UPD2:

在了解了处理空字符串的解决方案后,我发现更清楚的是完全跳过在前端发送空字符串并将default=None设置为序列化器。此外,不再需要自定义字段。

class Appartement(models.Model):
    minimum_commission = models.FloatField(null=True, default=None) 

class RentalTestSerializer(serializers.ModelSerializer):
    minimum_commission = serializer.FloatField(required=False, allow_null=True, min_value=0, default=None)

    class Meta:
        model = Appartement
        fields = (
            'minimum_commission',
        )

【问题讨论】:

  • 可以附上公寓的型号吗?重要的是查看您是否可以为该字段存储 null
  • 在模型中定义为minimum_commission = models.FloatField(null=True, default=None)

标签: python django django-rest-framework


【解决方案1】:

就像我在评论中提到的 - 公寓模型会很有用。

但是如果我理解正确的话,你想要实现的应该很简单,如下所示:

class Appartement(models.Model):
    minimum_commission = models.FloatField(blank=True, null=True, default=None)

class RentalTestSerializer(serializers.ModelSerializer):

    class Meta:
        model = Appartement
        fields = (
            'minimum_commission',
        )

有了这个实现,minimum_commission 是可选的,它也接受空值。

【讨论】:

  • 谢谢,@热心马丁。这在 shell 中有效,当我传递 None、-10、10 时。我刚刚将 min 验证器添加到模型中:minimum_commission = models.FloatField(null=True, default=None, blank=True, validators=[MinValueValidator(0.0)])。但问题仍然在于处理空字符串,如果表单上没有值则传递。我看到A valid number is required.
  • @IvanRostovsky 空字符串是字符串,所以会被拒绝。如果您确实需要接受空字符串,则需要处理它 - 不错的选择是您在帖子中使用的自定义字段。
  • 好的,谢谢。我开始避免处理空字符串,只是在前端添加条件,如果值为空,则不发送任何内容。同样在序列化器中,我添加了default=None 以支持重置列。感谢您的帮助,@热心马丁!
  • @IvanRostovsky 是的,很好。那更好。不确定您是否可以访问对方。很乐意提供帮助。
猜你喜欢
  • 1970-01-01
  • 2020-08-14
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-09
  • 2018-02-20
  • 1970-01-01
相关资源
最近更新 更多