상황
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
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가 반환하지 않아도 되는 필드로 인식하고 반환하지 않으며, 해당 값이 없더라도 에러를 반환하지 않게 된다.