【问题标题】:django rest framework serializers and django formsdjango rest 框架序列化器和 django 表单
【发布时间】:2014-06-04 20:49:15
【问题描述】:

问题:如何为表单和序列化程序中的字段验证编写 DRY 代码?

示例: 我有一个带有模型表单的简单 django 应用程序,它验证 passengers 字段为 Order

def clean_passengers(self):
    passengers = self.cleaned_data['passengers']
    if passengers > self.flight.available_seats:
        raise forms.ValidationError(
            _(u'''Passengers count can`t be greater then seats count'''))
    return passengers

Order 序列化器中的验证代码相同:

def validate_passengers(self, attrs, source):
    passengers = attrs[source]
    if passengers > self.flight.available_seats:
        raise serializers.ValidationError(
            _(u'''Passengers count can`t be greater then seats count'''))
    return attrs

这不是 DRY,我已经写了两次相同的逻辑。我怎样才能避免这种情况?也许我可以从表单或类似的东西继承序列化程序。

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    您可以使用您的序列化程序反序列化和验证表单的 is_valid 方法内的数据。

    class MyModelForm(ModelForm):
        def is_valid(self):
            # Call super's is_valid to populate cleaned_data and do basic field validation
            valid = super(MyModelForm, self).is_valid()
            if not valid:
                return False
    
            serializer = MyModelSerializer(data=self.cleaned_data)
            return serializer.is_valid()
    

    【讨论】:

    • 这很好用。谢谢。但是表单错误是空的。要添加它们需要添加:for error, value in serializer.errors.iteritems(): self._errors[error] = value
    • 不使用私有属性,_errors 你可以使用add_error(field, error) 方法。
    【解决方案2】:

    这是我对模型表单的可重用验证类的实现。除了重写 get_serializer 方法外,所有原生 Django 的东西都在这里。使用 Django 1.8.13 验证工作状态。

    class RestFrameworkValidationModelForm(forms.ModelForm):
        serializer_class = None
    
        def get_serializer(self, *args, **kwargs):
            """
            Return the serializer instance that should be used for validating and
            deserializing input, and for serializing output.
            """
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer()` method."
                % self.__class__.__name__
            )
    
            return self.serializer_class(*args, **kwargs)
    
        def is_valid(self):
            if super(RestFrameworkValidationModelForm, self).is_valid():
                serializer = self.get_serializer(data=self.cleaned_data)
                valid = serializer.is_valid()
                self.add_error(None, serializer.errors)
                return valid
            return False
    

    以下是使用示例:

    class ExperimentForm(RestFrameworkValidationModelForm):
        serializer_class = ExperimentSerializer
    
        class Meta:
            model = Experiment
            exclude = []
    

    【讨论】:

      【解决方案3】:

      我建议将所有验证(如果可能)放入模型(验证器或clean)。

      ModelFormModelSerializer 然后使用模式验证。

      【讨论】:

      • 感谢您的回答,但问题一般是关于表单和序列化程序的。我以模型形式和模型序列化器为例。
      • Denis AFAIK,使用模型/清洁方法时,您无法在字段和对象级别执行单步验证。
      • 我也喜欢在模型中尽可能多地进行验证,因为管理员和序列化程序很好地接受了它。但是一旦你需要请求用户,它就会变得很棘手。
      • Sadle 他们不再调用Modelclean 方法:github.com/encode/django-rest-framework/issues/3144
      • 这个答案是 entirely out of date since DRF no longer uses Model.clean() 并完全跳过该验证。
      猜你喜欢
      • 2015-06-29
      • 2020-03-22
      • 2015-10-29
      • 2020-05-08
      • 2015-07-06
      • 2019-06-11
      • 1970-01-01
      • 2018-12-13
      • 2016-03-31
      相关资源
      最近更新 更多