Django REST framework 공식문서
상황
- 프론트 단의 요청에 의해 하나의 모델 안에 들어있던 필드들을 각 종류에 맞게 세 가지로 묶어(depth를 하나 늘려서) 데이터를 주고 받는 케이스가 생겼었다.
- 그냥 GET 요청만 사용한다면
serializers.SerializerMethodField
를 사용해 데이터를 간단하게 묶어서 보여줄 수 있었지만, 해당 app에는 GET, POST, PUT 요청이 존재했다.
- 따라서 serializer를 묶을 필드별로 생성해 적용했다.
class CareSerializer(serializers.Serializer):
care_over_30 = serializers.IntegerField(label="...")
care_over_60 = serializers.IntegerField()
care_over_90 = serializers.IntegerField()
care_over_120 = serializers.IntegerField()
care_over_150 = serializers.IntegerField()
care_over_180 = serializers.IntegerField()
care_over_210 = serializers.IntegerField()
care_over_240 = serializers.IntegerField()
care_over_270 = serializers.IntegerField()
class BathSerializer(serializers.Serializer):
bath_car_under_60 = serializers.IntegerField()
bath_car_bath_under_60 = serializers.IntegerField()
bath_under_60 = serializers.IntegerField()
bath_car_over_60 = serializers.IntegerField()
bath_car_bath_over_60 = serializers.IntegerField()
bath_over_60 = serializers.IntegerField()
class NursingSerializer(serializers.Serializer):
nursing_under_30 = serializers.IntegerField()
nursing_under_60 = serializers.IntegerField()
nursing_over_60 = serializers.IntegerField()
class EmployeeRecipientSalarySerializer(serializers.ModelSerializer):
recipient = RecipientSerializer()
care = CareSerializer(label="...")
bath = BathSerializer()
nursing = NursingSerializer()
class Meta:
model = 모델
fields = [...]
- 여기서 문제가 발생했다. POST를 통해 데이터 생성은 가능했지만, 생성된 데이터를 조회하려 하니 데이터가 나오지 않았다.
해결
.to_representation(self, instance)
를 사용해 저장된 데이터를 보여주고, .to_internal_value(self, data)
를 사용해 들어온 데이터를 가공해 데이터베이스에 저장해 주었다.
def to_representation(self, instance):
ret = super().to_representation(
{
**instance.__dict__,
"recipient": instance.recipient,
"care": CareSerializer(instance).data,
"bath": BathSerializer(instance).data,
"nursing": NursingSerializer(instance).data,
}
)
ret.update()
return ret
def to_internal_value(self, data):
ret = super().to_internal_value(data)
ret.update(
{
**ret.pop("care"),
**ret.pop("bath"),
**ret.pop("nursing"),
}
)
return ret
생각
- 사실 위에 나온 작업을 할 필요는 전혀 없었다. 굳이 하나의 모델에 있는 필드들을 세 depth를 추가적으로 만들어 묶는 것은 그다지 효율적이지 못하다고 생각한다.
- 하지만 이 과정을 거치며 drf의 내장 함수 오버라이딩을 해볼 수 있다는 점이 좋았다.
- 지금까지 내가
validate()
함수 안에서 했던 작업들도 .to_internal_value(self, data)
에서 하는 것이 좋을 수도 있다는 점 또한 알게 되었다.
- 결국
validate()
함수 안에서는 진짜 유효성 검증만 하고, url path나 query parameter에서 가져오는 값은 .to_internal_value(self, data)
에서 가져와 유효성 검증을 하는 것이다.