Django rest框架和模型验证

2024-04-24 00:31:51 发布

您现在位置:Python中文网/ 问答频道 /正文

开始使用django rest框架,我在验证方面遇到了一些问题。

我有一个基本的模型,我已经将验证器应用到它的一个字段(一个常规的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,其中包含一些额外的字段和方法。这都是由一个非常简单的“retrieveupdateaview”提供的。

我注意到没有调用验证器(我可以在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似乎表明它没有。

这有点烦人,如果我想确保验证总是发生的话,它会迫使我复制很多字段代码,而且我宁愿尽可能保持干燥。

我可能遗漏了一些东西,但是在更新模型之前,是否有一个好的、干净的方法来确保序列化程序将运行这些验证器?

编辑:对源代码进行了双重检查,结果发现实例的full_clean方法确实是由视图调用的,然后再将其保存到数据库中,数据库最终运行模型的验证器。但还是弄不明白为什么那些人看起来不跑,tho。


Tags: django方法模型程序truesource序列化description
2条回答

实际上,我认为您提出的第一个解决方案@astrognocci,即使看起来很冗长,也是Django REST Framekork v3.0+的一个很好的解决方案

实际上,.full_clean()方法不再在ModelSerializer验证过程中调用,如this post中所述

因此,编写自定义类验证器(可以在ModelModelSerializer中使用)似乎是解决干性问题和一致性的一个相关选项。

这对我有效:

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.']}

相关问题 更多 >