开始使用django-rest-framework,我在验证方面遇到了一些麻烦。
我有一个基本模型,我已经将验证器应用于其字段的copple(常规MaxLengthValidator
和自定义RegexValidator
,结果是这样的:
class ZipCodeValidator(RegexValidator):
regex = '^([0-9]{5})$'
message = u'Invalid ZipCode.'
class User(AbstractUser, BaseUser):
"""
Custom user model
"""
# ... other fields ...
zipcode = models.CharField(
max_length=5, blank=True, validators=[ZipCodeValidator()]
)
description = models.TextField(
null=True, blank=True, max_length=1000, validators=[MaxLengthValidator(1000)]
)
然后我创建了映射到此模型的ModelSerializer
,其中包含一些其他字段和方法。这一切都由一个非常简单的`RetrieveUpdateAPIView。
我注意到没有调用验证器(我可以在zipcode字段中输入任何内容,或者在描述中输入超过1000个字符)。
快速而肮脏的解决方案是覆盖序列化程序级别的两个字段,并在那里分配验证器:
class UserSerializer(serializers.ModelSerializer):
zipcode = serializers.WritableField(
source='zipcode', required=False, validators=[ZipCodeValidator()]
)
description = serializers.WritableField(
source='description', required=False, validators=[MaxLengthValidator(1000)]
)
这很好,但我不喜欢它。我宁愿在模型级别进行此验证更安全(我不会在序列化程序上进行头脑自定义或额外验证,但在所有情况下都需要强制执行这些规则)。由于序列化程序的工作方式与django表格很相似,我希望它们可以调用模型的clean
&保存之前的cie方法,但快速查看source似乎表明它没有。
这有点烦人,它强迫我复制大部分字段代码,如果我想确保验证总是发生,我宁愿把它保持为尽可能干。
我可能会遗漏一些东西,但在更新模型之前是否有一种很好的方法可以确保序列化程序运行验证器?
编辑: Doubled检查了源,事实证明实例的full_clean
方法确实被视图调用,然后将其保存到db,而db又最终运行模型的验证器。仍然迷失为什么那些似乎没有跑,所以。
答案 0 :(得分:2)
这对我有用:
class ZipCodeValidator(RegexValidator):
regex = r'^[0-9]{5}$'
message = 'Invalid ZipCode.'
class MyModel(models.Model):
zipcode = models.CharField(max_length=5, blank=True, validators=[ZipCodeValidator()])
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
>>> s1 = MyModelSerializer(data={'zipcode': '34234'})
>>> s1.is_valid()
True
>>> s2 = MyModelSerializer(data={'zipcode': 'f3434'})
>>> s2.is_valid()
False
>>> s2.errors
{'zipcode': [u'Invalid ZipCode.']}
答案 1 :(得分:1)
实际上,我认为您提出的第一个解决方案@astrognocci,即使看起来很冗长,也是Django REST Framekork v3.0 +的一个很好的解决方案,
实际上,.full_clean()
验证过程中不再调用ModelSerializer
方法,如this post
因此,编写可在Model
和ModelSerializer
中使用的自定义类验证器似乎是DRY问题和一致性的一种相关选择。