[django] Got KeyError when attempting to get a value for field on serializer

nikevapormax·2023년 1월 12일
0

TIL

목록 보기
106/116
post-custom-banner

상황

  • UserRegisterSerializer를 작성하고, 테스트 코드를 돌리던 와중 모델과 시리얼라이저에 모두 있던 필드를 가져올 수 없다는 아래와 같은 에러가 발생했다.
KeyError: "Got KeyError when attempting to get a value for field `address_detail` on serializer `UserRegisterSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\nOriginal exception text was: 'address_detail'."

해결

  • 해당 에러의 발생 이유는 유저 데이터를 생성하고 UserRegisterSerializer에 선언되어 있는 필드들이 그대로 리턴되지 않아서이다.
  • 해당 에러를 해결하기 위해서 두 가지 해결방법이 있다.
    • 만약 현재 나의 상황 같이 시리얼라이저에서 생성된 데이터 이외의 값 (access, refresh 토큰)들을 반환하는 경우가 있을 것이다. 이 때 다음과 같이 반환되지 않을 필드들에 write_only=True를 적용해주는 것이다.
      • 생성된 필드들을 굳이 반환해 줄 필요가 없다면 write_only=True를 적용해 주어도 문제가 되지 않는다.
      nickname = serializers.CharField(write_only=True, label="유저 닉네임")
       username = serializers.CharField(write_only=True, label="유저 이름")
       post_number = serializers.CharField(write_only=True, label="우편번호")
       address = serializers.CharField(write_only=True, label="주소")
       address_detail = serializers.CharField(label="상세 주소")
    • 만약 생성한 데이터를 그대로 반환해주어야 한다면 아래와 같이 생성된 데이터를 그대로 반환하게 되면 에러를 해결할 수 있다.
      @transaction.atomic
       def create(self, validated_data):
           user = User.objects.create_user(
               **validated_data,
           )
           
           return user

에러 발생 이유

def to_representation(self, instance):
    """
    Object instance -> Dict of primitive datatypes.
    """
    ret = OrderedDict()
    fields = self._readable_fields

    for field in fields:
        try:
            attribute = field.get_attribute(instance)
        except SkipField:
            continue

        # We skip `to_representation` for `None` values so that fields do
        # not have to explicitly deal with that case.
        #
        # For related fields with `use_pk_only_optimization` we need to
        # resolve the pk value.
        check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
        if check_for_none is None:
            ret[field.field_name] = None
        else:
            ret[field.field_name] = field.to_representation(attribute)

    return ret
  • django에 내장되어 있는 class Serializer(BaseSerializer, metaclass=SerializerMetaclass) 안에 선언되어 있는 함수이다.
  • create가 된 필드 값들을 리턴할 때 리턴하는 필드들은 self._readable_fields에서 볼 수 있듯이 readable 해야한다.
  • 생성된 값들을 그대로 반환하지 않는다면 serializer에서 리턴할 값들을 필드에서 매치해서 뽑아주는데 리턴값에서 선언된 필드들을 찾지 못하게 된다.
  • 따라서 write_only=True를 선언해 준다면 serializer가 반환하지 않아도 되는 필드로 인식하고 반환하지 않으며, 해당 값이 없더라도 에러를 반환하지 않게 된다.
profile
https://github.com/nikevapormax
post-custom-banner

0개의 댓글