сериализаторы django rest framework и формы django

Вопрос: как написать СУХОЙ код для проверки полей как в форме, так и в сериализаторе?

Пример: у меня есть простое приложение 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, и я дважды написал одну и ту же логику. Как я могу этого избежать? Может быть, я могу унаследовать сериализатор от формы или что-то в этом роде.


person zymud    schedule 04.06.2014    source источник


Ответы (3)


Вы можете использовать свой сериализатор для десериализации и проверки данных внутри метода 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()
person xjtian    schedule 04.06.2014
comment
Это прекрасно работает. Спасибо. Но форма ошибок пуста. Для их добавления нужно добавить: for error, value in serializer.errors.iteritems(): self._errors[error] = value - person zymud; 05.06.2014
comment
Вместо использования частного атрибута _errors вы можете использовать add_error(field, error) метод. - person nnutter; 09.12.2016

Вот моя реализация повторно используемого класса проверки для форм модели. Все нативные вещи 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 = []
person Alexander Fedosov    schedule 15.11.2016

Я бы предложил поместить всю проверку (когда это возможно) в модель (валидаторы или clean).

ModelForm и ModelSerializer затем используйте проверку режима.

person Denis Cornehl    schedule 05.06.2014
comment
Спасибо за ваш ответ, но вопрос был о формах и сериализаторах в целом. В качестве примера я использовал форму модели и сериализатор модели. - person zymud; 05.06.2014
comment
Денис, насколько я знаю, вы не можете выполнять одноэтапную проверку на уровне поля и объекта при использовании методов Model/clean. - person jturmel; 04.09.2015
comment
Я также предпочитаю вкладывать в модель как можно больше проверок, поскольку администратор и сериализатор прекрасно это понимают. Но как только вам понадобится пользователь запроса, все становится сложно. - person djangonaut; 28.12.2015
comment
К сожалению, они больше не вызывают метод clean Model: github.com/encode/django- остальные рамки/проблемы/3144 - person Reeshabh Ranjan; 11.03.2021
comment
Этот ответ полностью устарел, поскольку DRF больше не использует Model.clean() и полностью пропускает эту проверку. - person Brad Solomon; 04.08.2021