Django Rest Framework 序列化器与 Django 表单

10 投票
3 回答
6671 浏览
提问于 2025-04-18 08:38

问题: 如何为表单和序列化器编写不重复的代码来进行字段验证?

示例: 我有一个简单的 Django 应用,里面有一个模型表单,用来验证 Order 中的 passengers 字段:

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

这样写就不够简洁,因为我重复写了同样的逻辑两次。我该怎么避免这种情况呢?也许我可以让序列化器继承自表单,或者其他什么方法。

3 个回答

2

我建议把所有的验证(如果可以的话)放到模型里面(使用验证器或者clean方法)。

ModelFormModelSerializer会使用这些模型里的验证规则。

5

这是我实现的一个可重复使用的验证类,用于模型表单。里面包含了所有原生的Django功能,除了我重写了get_serializer这个方法。这个实现经过验证,可以在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 = []
8

你可以在表单的 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()

撰写回答