我应该在哪里对对象和字段进行django验证?

时间:2015-10-03 11:22:17

标签: python django validation django-rest-framework

我正在创建一个django应用程序,它使用Django Rest Framework和普通的django-views作为用户的入口点。

我想验证模型中的独立字段以及整体上的对象。例如:

  • 字段:输入的牌照是基于正则表达式函数的正确牌照。与其他领域无关。

  • 对象:输入的邮政编码是否对指定国家/地区有效。与模型中的邮政编码和国家/地区相关。

对于DRF-API,我使用ModelSerializers自动调用我在模型中放置的所有验证器,例如:

class MyModel(models.Model):
    licence_plate = CharField(max_length=20, validators=[LicencePlateValidator])

由于模型中给出了验证器,因此验证了API POSTS(因为我使用的是ModelSerializer)以及在django admin后端中创建的对象。

但是当我想引入对象级别验证时,我需要在序列化程序的 validate() - 方法中执行此操作,这意味着对象仅在API中进行验证。

我也必须覆盖模型的save方法,以验证在Django管理页面中创建的对象。

问题:这对我来说似乎有些混乱,有一点我可以放置对象级验证器,以便它们在API和管理页面中运行,就像我做了字段级验证(我只需要将他们放在我的模型声明中,一切都得到处理)

2 个答案:

答案 0 :(得分:6)

对于模型级验证,有Model.clean方法。

如果您使用ModelFormadmin中默认使用),则会调用它,因此这将解决django视图和管理部分。

另一方面,DRF不会打电话给模特' clean会自动Serializer.validate,因此您必须自己在class ValidateModelMixin(object) def validate(self, attrs): attrs = super().validate(attrs) obj = self.Meta.model(**attrs) obj.clean() return attrs class SomeModelSerializer(ValidateModelMixin, serializers.ModelSerializer): #... class Meta: model = SomeModel 中自行完成(正如doc建议的那样)。你可以通过串行器mixin来实现:

class DelegateToModelValidator(object):

    def set_context(self, serializer):
        self.model = serializer.Meta.model

    def __call__(self, attrs):
        obj = self.model(**attrs)
        obj.clean()

class SomeModelSerializer(serializers.ModelSerializer):
    #...
    class Meta:
        model = SomeModel
        validators = (
            DelegateToModelValidator(),
        )

或写一个验证器:

clean

警告:

  • 模型的额外实例化,只需拨打{{1}}
  • 即可
  • 您仍然需要将mixin / validator添加到序列化程序

答案 1 :(得分:2)

您可以创建一个单独的函数validate_zipcode_with_country(zipcode, country) ,这将需要2个参数zipcodecountry

然后,我们将在序列化程序的validate()和我们的模型clean() 中调用此方法。

from django.core.exceptions import ValidationError

def validate_zipcode_with_country(zipcode, country):
    # check zipcode is valid for the given country 
    if not valid_zipcode:
        raise ValidationError("Zipcode is not valid for this country.") 

然后在serializers.py中,您需要在validate()函数中调用此函数。

class MySerializer(serializers.ModelSerializer):   

    def validate(self, attrs):
        zipcode = attrs.get('zipcode')
        country = attrs.get('country')
        validate_zipcode_with_country(zipcode, country) # call the function
        ...

同样,您需要覆盖模型clean()并调用此函数。

class MyModel(models.Model):

    def clean(self):        
        validate_zipcode_with_country(self.zipcode, self.country) # call this function
        ...