【问题标题】:Where should i do the django validations for objects and fields?我应该在哪里对对象和字段进行 django 验证?
【发布时间】:2015-10-03 11:22:16
【问题描述】:

我正在创建一个 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 管理后端创建的对象都被验证了。

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

我还必须重写模型的保存方法,以验证在 Django 管理页面中创建的对象。

问题:这对我来说似乎有点混乱,是否有一个地方我可以放置对象级验证器,以便它们在 API 和管理页面中运行,例如我进行了字段级验证(我只需将 它们 放入我的模型声明中,一切都已处理)

【问题讨论】:

    标签: python django validation django-rest-framework


    【解决方案1】:

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

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

    另一方面,DRF 不会自动调用模型的clean,因此您必须自己在Serializer.validate 中调用(正如doc 所建议的那样)。您可以通过序列化程序 mixin 来做到这一点:

    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
    

    或者写一个验证器:

    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
    • 您仍然需要将 mixin/validator 添加到您的序列化程序中

    【讨论】:

    • Ah tnx,这个答案以及 Rahul 让我更清楚地知道在两个地方调用模型验证器(一次在序列化程序中,一次在模型中)是 i> 确实是通过表单 API 进行验证的唯一方法。它给了我一些想法,如何以更简洁的方式编写一些代码。我想我会走 MixIn 路线......对我来说似乎更干净。
    • 这会在与具有关系的模型一起使用时产生TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use users.set() instead.。有什么解决方法吗?
    【解决方案2】:

    您可以创建一个单独的函数validate_zipcode_with_country(zipcode, country),该函数将接受两个参数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
            ...
    

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 1970-01-01
      相关资源
      最近更新 更多