직렬화 클래스 필드 및 고급 기술

  1. 직렬화 클래스의 일반적인 필드 유형과 매개변수 ================
# BooleanField    BooleanField()
# NullBooleanField    NullBooleanField()
# CharField    CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
# EmailField    EmailField(max_length=None, min_length=None, allow_blank=False)
# RegexField    RegexField(regex, max_length=None, min_length=None, allow_blank=False)
# SlugField    SlugField(maxlength=50, min_length=None, allow_blank=False) 정규식 필드, 정규 패턴 [a-zA-Z0-9-]+ 검증
# URLField    URLField(max_length=200, min_length=None, allow_blank=False)
# UUIDField    UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 예: "5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 
# IPAddressField    IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
# IntegerField    IntegerField(max_value=None, min_value=None)
# FloatField    FloatField(max_value=None, min_value=None)
# DecimalField    DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 최대 자릿수 <br></br>                  decimal_palces: 소수점 위치
# DateTimeField    DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
# DateField    DateField(format=api_settings.DATE_FORMAT, input_formats=None)
# TimeField    TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
# DurationField    DurationField()
# ChoiceField    ChoiceField(choices) choices는 Django와 동일한 방식 사용
# MultipleChoiceField    MultipleChoiceField(choices)
# FileField    FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
# ImageField    ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)<br></br>*******************************************************아래 내용은 숙지하고 익숙해져야 합니다**********************************************************************************<br></br>
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
BooleanField    BooleanField()
IntegerField    IntegerField(max_value=None, min_value=None)
DecimalField    DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 최대 자릿수 <br></br>                  decimal_palces: 소수점 위치

리스트: Listfield :{name:'휘태양',age:19,hobby:['헬스','미양양']}

딕셔너리: Dictfield :{name:'휘태양',age:19,wife:{'name':'미양양','age':15}}

 
  1. 직렬화 클래스 고급 기술 ==========

(1)source, 직렬화 필드 이름 변경

source는 프론트엔드에 반환되는 필드명을 자유롭게 변경할 수 있게 합니다. 프론트엔드에 표시할 필드명에 source 속성을 추가하여 source = '실제 필드명'으로 설정할 수 있습니다. 다만, source를 사용해 프론트엔드에서 이미 사용 중인 필드명과 동일하게 만들 수는 없습니다(불필요한 반복 작성은 피해야 합니다). source는 테이블 간 조회에도 활용할 수 있습니다.

프론트엔드에 표시할 필드명 = serializers.CharField(max_length=32,source='DB_테이블_필드명')
테이블 간 조회가 필요한 경우 조인이 필요합니다
프론트엔드에 표시할 필드명 = serializers.CharField(max_length=32,source='관련_테이블.필드명')

(2) 직렬화 필드 커스터마이징 방법 두 가지

방법 1

직렬화 클래스에서 SerializerMethodField 사용(실수로 ModelSerializer가 되지 않도록 주의)<br></br><em>serializers.py</em><em>파일의 클래스 내에 다음과 같이 추가합니다</em>
publish = serializers.SerializerMethodField()<br></br>def get_publish(self,obj):<br></br>    return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}<br></br><br></br>데이터가 여러 개인 경우(예: publish.name에 두 개의 값이 있는 경우) for 루프를 사용하여 각 항목을 추출한 후 리스트에 추가하여 반환해야 합니다
def get_authors(self, obj):<br></br>    author_list = []<br></br>    for author in obj.authors.all():<br></br>        author_list.append({'id': author.id, 'name': author.name, 'age': author.age})<br></br>    return author_list

read_only와 write_only

read_only = True
read_only는 데이터가 프론트엔드로 반환될 때만 표시됩니다
write_only = True
write_only는 프론트엔드에서 백엔드로 데이터를 전송할 때만 표시됩니다

관계형 테이블의 역직렬화 저장

    publish = serializers.IntegerField(write_only=True)
    # publish = serializers.CharField()
    # authors = serializers.ListField(write_only=True)
    authors = serializers.ListField(write_only=True)


    publish_date = serializers.DateField()
    publish_info = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

위 코드에서 IntegerField와 ListField를 사용하는 경우 반드시 (write_only=True)를 추가해야 합니다. 그렇지 않으면 데이터는 데이터베이스에 저장되지만 프론트엔드로 반환할 때 오류가 발생하고 표시되지 않습니다. 동시에 create 메서드를 재정의하지 않으면 오류가 발생합니다.

 def create(self, validated_data):
        book = Book.objects.create(name=validated_data.get('name'),
                                  price=validated_data.get('price'),
                                  publish_date=validated_data.get('publish_date'),
                                  publish_id=validated_data.get('publish'),
                                  )
        authors = validated_data.get('authors')
        book.authors.add(*authors)
        return book
  1. 역직렬화 데이터 검증 ===========

데이터 검증 규칙은 forms와 유사합니다. 먼저 사용자가 정의한 규칙을 검증한 다음, 부분 후크(로컬 후크)를 검증하고 마지막으로 전역 후크를 검증합니다.

# 사용자 정의 규칙
    name = serializers.CharField(label='책 제목',required=True,error_messages={
        'required': '책 제목은 필수 항목입니다'})
    price = serializers.DecimalField(label='가격',required=True,max_digits=7, decimal_places=2,error_messages={
        'max_digits':'가격이 너무 높습니다',
        'required': '가격을 입력해주세요'})
    publish = serializers.CharField(max_length=8, min_length=3, label='출판사 이름', required=True, error_messages={
        'max_length': '출판사 이름이 너무 깁니다',
        'min_length': '출판사 이름이 너무 짧습니다',
        'required': '이 항목은 필수입니다'
    })
# 부분 후크<br></br>
def validate_name(self, name):<br></br>    if '금지어' in name:<br></br>        raise ValidationError('이름에 금지어가 포함되어 있습니다')<br></br>    return name<br></br><br></br>def validate_price(self, price):<br></br>    if price == 0:<br></br>        raise ValidationError('가격은 0일 수 없습니다')<br></br>    return price
# 전역 후크<br></br>전역 후크는 비밀번호 확인 시 주로 사용됩니다<br></br>def validate(self): <br></br>  password=self.validated_data.get('password') <br></br>  confirm_password=self.validated_data.get('confirm_password') <br></br>  if confirm_password==password: # 검증 성공 <br></br>    return self.validated_data <br></br>  else: <br></br>    raise ValidationError('비밀번호가 일치하지 않습니다')<br></br>
 
  1. 모델 직렬화기(ModelSerializer) 사용법 =============================

Serializer와 기본적으로 동일하지만 create와 update 메서드를 재정의할 필요가 없습니다. 다만 Meta 클래스를 추가해야 하며, 그렇지 않으면 오류가 발생합니다. Meta 클래스의 model은 직렬화할 테이블의 모델을 지정하고, fields는 직렬화할 필드 이름 목록입니다.

class BookSerializer(serializers.ModelSerializer):<br></br>    name = serializers.CharField(label='책 제목', max_length=8, min_length=3, error_messages={<br></br>        'required': '책 제목은 필수 항목입니다'})<br></br>    price = serializers.DecimalField(label='가격', required=True, max_value=199, min_value=9, max_digits=7,<br></br>                                     decimal_places=2, error_messages={<br></br>            'max_digits': '가격이 너무 높습니다',<br></br>            'required': '가격을 입력해주세요'})<br></br>    # publish = serializers.IntegerField(write_only=True)<br></br>    # publish = serializers.CharField(write_only=True)<br></br>    # authors = serializers.ListField(write_only=True)<br></br>    authors = serializers.ListField(write_only=True)<br></br><br></br>    publish_date = serializers.DateField()<br></br>    publish_info = serializers.DictField(read_only=True)<br></br>    author_list = serializers.ListField(read_only=True)<br></br><br></br>    extra_kwargs = {'name': {'max_length': 6},<br></br>                    'publish':{'write_only':True}}<br></br><br></br>    class Meta:<br></br>        model = Book<br></br>        fields = ['name', 'price', 'publish', 'authors', 'publish_date', 'publish_info', 'author_list']<br></br><br></br>    def validate_name(self, name):<br></br>        if '금지어' in name:<br></br>            raise ValidationError('이름에 금지어가 포함되어 있습니다')<br></br>        return name<br></br><br></br>    def validate_price(self, price):<br></br>        if price == 0:<br></br>            raise ValidationError('가격은 0일 수 없습니다')<br></br>        return price

extra_kwargs

ModelSerializer에는 extra_kwargs가 있어 다른 필드에 매개변수를 추가할 수 있습니다.

예:<br></br>extra_kwargs = {'name':{max_length:6}
  1. 역직렬화 데이터 검증 소스 코드 분석 (이해용) ==================
# 먼저 필드 자체 규칙(최대, 최소)을 검증하고 부분 후크를 실행한 다음 전역 후크를 실행합니다
# 부분: validate_필드명, 전역: validate

# 시작점: 어떤 작업이 데이터 검증을 실행하는가? ser.is_valid()
    -BaseSerializer의 is_valid() 메서드
        def is_valid(self, *, raise_exception=False):
            if not hasattr(self, '_validated_data'):
                try:
                    # 실제 검증 실행, 성공 시 검증된 데이터 반환
                    self._validated_data = self.run_validation(self.initial_data)
                except ValidationError as exc:
            return not bool(self._errors)
    
    -내부 실행: self.run_validation(self.initial_data)---》실제로는 Serializer의 메서드 실행
        -ctrl 키를 누르고 마우스로 클릭하면 현재 클래스에서 run_validation을 찾으려고 시도하고, 없으면 부모 클래스에서 찾습니다
        -이것은 코드 실행이 아니라 코드를 찾는 과정입니다. 실제 실행은 자기 자신부터 시작하여 위로 올라갑니다
            def run_validation(self, data=empty):
                #부분 후크 실행
                value = self.to_internal_value(data)
                try:
                    #전역 후크 실행, 루트부터 시작하여 실행하며, 우선순위는 자신이 정의한 직렬화 클래스의 전역 후크
                    value = self.validate(value)
                except (ValidationError, DjangoValidationError) as exc:
                    raise ValidationError(detail=as_serializer_error(exc))

                return value
  -전역 후크 확인 후 부분 후크---》 self.to_internal_value---》루트부터 찾기---》실제로는 Serializer의 메서드 실행
     def to_internal_value(self, data):
        for field in fields: # fields: 직렬화 클래스의 모든 필드, for 루프로 필드 객체를 하나씩 가져옴
            #리플렉션: self(직렬화 클래스 객체)에서 validate_필드명 메서드를 찾음
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            try:
                #필드 자체 검증 규칙(최대/최소 길이) 실행
                validated_value = field.run_validation(primitive_value)
                #부분 후크
                if validate_method is not None:
                    validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail

        return ret
    
 # 사용자가 작성한 직렬화 클래스---》ModelSerializer 상속---》Serializer 상속---》BaseSerializer---》Field
  1. 단언문(assert) ==========
일반적인 기본적인 작성 방법
data_list = 'bxf'
if  'b' in data_list:
    print('존재함')
print('존재하지 않음')
print('종료')


고급스러운 단언문 작성 방법

data_list = 'bxf'
assert 'b' in data_list, '존재하지 않음'
print('종료')

태그: Django REST Framework 직렬화 데이터 검증 modelserializer API 개발

6월 23일 16:17에 게시됨