program story

Django REST Framework 사용자 정의 필드 유효성 검사

inputbox 2020. 12. 30. 08:08
반응형

Django REST Framework 사용자 정의 필드 유효성 검사


모델에 대한 사용자 지정 유효성 검사를 생성하여 모델 start_date이 이전 에 있는지 확인하고 end_date거의 불가능한 것으로 증명하려고합니다.

내가 시도한 것들 :

  • 내장 Django 유효성 검사기 :이 항목을 확인하지 않습니다.

  • 다음과 같이 내 자신을 작성합니다.

    def validate_date(self):
       if self.start_date < self.end_date:
            raise serializers.ValidationError("End date must be after start date.")
    

Serializer 클래스 (및 모델)에 추가 한이 코드는 어느 위치에서도 호출되지 않는 것 같습니다.

또한 사용할 수있는 코드를 찾았 지만 방법에 통합하는 방법을 모르겠습니다. 하나의 모델 속성을 확인하는 데 작동하는 것 같지만 두 속성을 확인해야합니다.

내 모델 :

class MyModel(models.Model):

    created = models.DateTimeField(auto_now_add=True)
    relation_model = models.ForeignKey(RelationModel, related_name="mymodels")
    priority = models.IntegerField(
        validators = [validators.MinValueValidator(0), validators.MaxValueValidator(100)])
    start_date = models.DateField()
end_date = models.DateField()

    @property
    def is_active(self):
        today = datetime.date.today()
        return (today >= self.start_date) and (today <= self.end_date)

    def __unicode__(self):
        ...

    class Meta:
        unique_together = ('relation_model', 'priority', 'start_date', 'end_date')

참고로, 다른 모든 유효성 검사가 작동합니다!

내 시리얼 라이저 :

class MyModelSerializer(serializers.ModelSerializer):

    relation_model = RelationModelSerializer
    is_active = serializers.Field(source='is_active')

    def validate_date(self):
        if self.start_date > self.end_date:
            raise serializers.ValidationError("End date must be after start date.")   

    class Meta:
        model = MyModel
        fields = (
            'id', 'relation_model', 'priority', 'start_date', 'end_date', 'is_active'
        )

내 견해 :

class MyModelList(generics.ListCreateAPIView):
    permission_classes = (IsAdminUser,)
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
    ordering = ('priority')

serializer의 필드가 아니기 때문에 절대 호출 되지 않으므로 개체 전체 유효성 검사 ( validate())를 사용해야합니다 . 문서에서 :validate_datedate

class MySerializer(serializers.ModelSerializer):
    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start_date'] > data['end_date']:
            raise serializers.ValidationError("finish must occur after start")
        return data

DRF 3.0 이전에는 모델의 깨끗한 기능에 추가 할 수도 있지만 DRF 3.0에서는 더 이상 호출되지 않습니다.

class MyModel(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    def clean(self):
        if self.end_date < self.start_date:
            raise ValidationError("End date must be after start date.")

jgadelange의 대답은 아마도 django rest 3 전에 작동했습니다. django rest framework 3 * 버전을 사용하는 사람이 있다면 이것이 도움이 될 것이라고 생각합니다. 모델 수준에서 검증 프로세스를 유지해야하며 깨끗한 방법이 하나의 솔루션이 될 수 있습니다. 그러나 장고 나머지 프레임 워크 발표는 말한다 여기 사람이 모델 .clean 방법, 검증 나머지 통화하고자하는 경우, 그 / 그녀가 깨끗한 방법은 다음과 같은 방법으로이 시리얼 클래스를 형성 호출 시리얼 라이저의 validate 메소드와 필요를 오버라이드 (override) 할 필요가 있음

(문서가 : clean () 메서드는 serializer 유효성 검사의 일부로 호출되지 않기 때문에)

class MySerializer(serializers.ModelSerializer):

   def validate(self, attrs):
     instance = MyModel(**attrs)
     instance.clean()
     return attrs

및 모델

class MyModel(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()

    def clean(self):
        if self.end_date < self.start_date:
            raise ValidationError("End date must be after start date.")

serializer의 validate()방법 을 재정의하기로 선택한 경우 상황과 관련하여 여기에 또 다른 대답이 유용 할 수 있습니다 .

Django REST Framework의 Order of Serializer 유효성 검사 에 대한 답변과 관련하여 serializer.validate()유효성 검사 시퀀스가 ​​끝날 때 메서드가 호출 되었다고 말해야합니다 . 그러나 필드의 유효성 검사기는에, 그 전에라고 serializer.to_internal_value()제기 ValidationError끝.

이는 사용자 정의 유효성 검사 오류가 기본 오류와 함께 누적되지 않음을 의미 합니다 .

내 생각에 원하는 동작을 달성하는 가장 깨끗한 방법 은 serializer 클래스에서 대상 필드 메서드 유효성 검사를 사용하는 것입니다 .

def validate_end_date(self, value):
    # validation process...
    return value

이 경우와 같이 모델에서 다른 필드 값이 필요한 경우 다음을 사용하여 start_date가져올 수 있습니다 (프로세스가 완료되지 않았기 때문에 아직 검증되지 않음).

# `None` here can be replaced with field's default value
start_date = 'start_date' in self.initial_data
    and self.initial_data['start_date'] or None

현장에서 클래스 기반 유효성 검사기로 이것을 구현하는 데 어려움을 겪는 사람을 위해 ...

from rest_framework.serializers import ValidationError

class EndDateValidator:
    def __init__(self, start_date_field):
        self.start_date_field = start_date_field

    def set_context(self, serializer_field):
        self.serializer_field = serializer_field

    def __call__(self, value):
        end_date = value
        serializer = self.serializer_field.parent
        raw_start_date = serializer.initial_data[self.start_date_field]

        try:
            start_date = serializer.fields[self.start_date_field].run_validation(raw_start_date)
        except ValidationError:
            return  # if start_date is incorrect we will omit validating range

        if start_date and end_date and end_date < start_date:
            raise ValidationError('{} cannot be less than {}'.format(self.serializer_field.field_name, self.start_date_field)

당신이 가정 start_dateend_date당신의 시리얼 필드가, 당신이 다음에에서 설정할 수있는 end_date필드 validators=[EndDateValidator('start_date')].


Konrad 답변을 확장하겠습니다. 나는 그것이 매우 명시 적이기 때문에 그것을 좋아하고 또한 우리가 그들을 사용할 때 다른 필드에 대한 유효성 검사를 호출하고 있습니다. 따라서 더 안전하며 중복 될 수 있습니다 (일부 유효성 검사는 두 번 호출 됨).

가장 먼저 주목할 점은 이렇게 구현하면 run_validator를 실행하면 validators 변수에 설정된 유효성 검사 만 나타납니다. 예를 들어 validate_ 메소드를 사용하여 필드의 유효성을 검사하면 실행되지 않습니다.

Also, I have make it inheritable, so we can reimplement the validation function and rehuse the code.

validators.py

from rest_framework.serializers import ValidationError

class OtherFieldValidator:

    #### This part is the same for all validators ####

    def __init__(self, other_field):
        self.other_field = other_field # name of parameter

    def set_context(self, serializer_field):
        self.serializer_field = serializer_field # name of field where validator is defined

    def make_validation(self,field, other_field):
        pass

    def __call__(self, value):
        field = value
        serializer = self.serializer_field.parent # serializer of model
        raw_other_field = serializer.initial_data[self.other_field] # data del otro campo

        try:
            other_field = serializer.fields[self.other_field].run_validation(raw_other_field)
        except ValidationError:
            return # if date_start is incorrect we will omit validating range

    #### Here is the only part that changes ####

        self.make_validation(field,other_field)

class EndDateValidator(OtherFieldValidator):

    def make_validation(self,field, other_field):
        date_end = field
        date_start = other_field
        if date_start and date_end and date_end < date_start:
            raise ValidationError('date cannot be')

So the serializer will be like this : serializers.py

# Other imports
from .validators import EndDateValidator

 def myfoo(value):                                                        
     raise ValidationError("start date error")                             

 class MyModelSerializer(serializers.ModelSerializer):                                        
     class Meta:                                                          
         model = MyModel                                                      
         fields = '__all__'                                                                                       
         extra_kwargs = {                                                 
             'date_end': {'validators': [EndDateValidator('date_start')]},
             'date_start': {'validators': [myfoo]},                       
         }                                                                

ReferenceURL : https://stackoverflow.com/questions/31278418/django-rest-framework-custom-fields-validation

반응형