• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

중첩된 serializer(DB table은 하나)

23.05.31 23:16 작성 조회수 147

0

 

class TbVaResult(models.Model):
    report_id = models.ForeignKey(TbVaReport, on_delete=models.PROTECT, db_column="report_id")
    result_type = models.CharField(max_length=10)
    asset_cd = models.CharField(max_length=20)
    measure_cd = models.CharField(max_length=10)
    result_cd = models.CharField(max_length=10, blank=True, null=True)
    result_desc = models.CharField(max_length=4000, blank=True, null=True)
 
    class Meta:
        db_table = 'tb_va_result'
        unique_together = (('report_id', 'result_type', 'asset_cd', 'measure_cd'),)

 

위와 같은 model이 있고,

 

 {
        "report_id": "IS_LX_2023_0010",
        "result_type": "C",
        "asset_cd": "LX001",
        "result": [
            {
                "measure_code": "LX1-01-R",
                "result": "Y",
                "result_code": "LX1-01-SA",
                "result_desc": "root"
            },
            {
                "measure_code": "LX1-03-R",
                "result": "SELF",
                "result_code": "LX1-03-SA",
                "result_desc": "인터뷰"
            }
        ]
    }

이런 데이터를 보내려고 합니다.

serializer를 통해 아래와 같은 데이터를 만들어 테이블(TbVaResult)에 쓰려고 합니다.

{
		"report_id": "IS_LX_2023_0012",
		"result_type": "C",
		"asset_cd": "LX001",
		 "measure_cd": "LX1-01-R",
		 "result_cd": "Y",
		 "result_desc": "root"
	},
	{
		"report_id": "IS_LX_2023_0012",
		"result_type": "C",
		"asset_cd": "LX001",
		"measure_cd": "LX1-03-R",
		"result_cd": "SELF",
		"result_desc": "인터뷰"
	}

views.py

class ResultCreateViewSet(viewsets.ModelViewSet):
    queryset = TbVaResult.objects.all()
    serializer_class = ResultCreateSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

serializers.py

class ResultSerializer(serializers.Serializer):
    measure_cd = serializers.CharField()
    result_cd = serializers.CharField()
    result_desc = serializers.CharField()

class ResultCreateSerializer(serializers.Serializer):
    result = ResultSerializer(many=True)
    report_id = serializers.CharField()
    result_type = serializers.CharField()
    asset_cd = serializers.CharField()

    def create(self, validated_data):
        print('===============================================')
        print('validated_data:', validated_data)
        result_data = validated_data.pop('result')
        print('result_data:', result_data)
        report_id = validated_data.pop('report_id')
        result_type = validated_data.pop('result_type')
        asset_cd = validated_data.pop('asset_cd')

        tb_va_report = TbVaReport.objects.get(report_id=report_id)

        for result_item in result_data:
            measure_cd = result_item.pop('measure_cd')
            result_cd = result_item.pop('result_cd')
            result_desc = result_item.pop('result_desc')

            tb_va_result = TbVaResult.objects.create(
                report_id=tb_va_report,
                result_type=result_type,
                asset_cd=asset_cd,
                measure_cd=measure_cd,
                result_cd=result_cd,
                result_desc=result_desc
            )

        return tb_va_result

"Got AttributeError when attempting to get a value for field result on serializer ResultCreateSerializer." 이런 에러가 발생하네요.

DB에 쓸때 result 가 안들어가는데 어디서 발생되는 에러인지 모르겠습니다.

도움을 부탁드립니다. ㅠㅠ

 

 

답변 2

·

답변을 작성해보세요.

0

아래 오류는

"Got AttributeError when attempting to get a value for field result on serializer ResultCreateSerializer."

ResultCreateViewSet 에서

  • serializer_class 로서 ResultCreateSerializer 가 지정되어있고

  • queryset으로서 TbVaResult.objects.all()가 지정되어있는 데

ResultCreateSerializer에 지정하신 result 이름의 속성이 TbVaResult 모델 클래스에는 없기 때문에 발생하는 오류입니다.
ResultCreateSerializer 클래스에 정의된 내역대로 TbVaResult를 통해 쿼리셋을 만드는 과정에서 발생하는 거죠.

에러 메세지를 너무 짧게만 잘라서 보여주셨는 데요. 긴 에러메세지에서 뒷 부분에 아래와 같은 메세지가 더 있지 않으신가요?

Original exception text was: 'TbVaResult' object has no attribute 'result'.

isecure님의 프로필

isecure

질문자

2023.06.02

네 정확하십니다~

Got AttributeError when attempting to get a value for field result on serializer ResultCreateSerializer. The serializer field might be named incorrectly and not match any attribute or key on the TbVaResult instance. Original exception text was: 'TbVaResult' object has no attribute 'result'.

이 문제때문에 몇일을 gpt하고 씨름하고 있는데 영 감을 못잡겠네요.

현재는 to_internal_value() 를 활용해서 중첩된 구조의 json을 일렬로 만들어서 validated_data로 만들려고 하고 있습니다.

생각하시는 방향으로 검토해보시구요.

저는 Serializer 안에서 값을 변경하기 보다, Serializer에 데이터를 넘기기전에 데이터를 먼저 정리 (필드명 맞추기 등) 해서 넘겨주는 방식이 낫지 않을까 싶습니다.

그리고, 필드명도 좀 더 의미있게 쓰시면 코드 가독성에 도움이 되실 것입니다.

0

안녕하세요.

요청 데이터의 형태와 시리얼라이저의 형태가 서로 맞지 않는 경우,

ViewSet에게 시리얼라이저 처리를 맡기기보다, ViewSet의 create 메서드 구현을 참고하시어, ViewSet에 create 메서드를 직접 구현하시어 직접 시리얼라이저 처리를 해보시면, 구현도 간결해지고 처리 과정을 보다 명확하게 이해하실 수 있으실 듯 합니다.

https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py#L18

request.data에서 시리얼라이저에 필요한 데이터만 뽑아서 넘기고 유효성 검사도 직접 호출해주시는 거죠.
many=True 는 조회에 대해서만 동작할 뿐, 조회 이외에서는 동작하지 않습니다. many=True가 필요한 부분도 request.data에서 목록을 얻어서 각각 시리얼라이저 유효성 검사를 수행하시고 저장하시는 접근을 해보실 수 있습니다.

Serializer는 장고의 Form과 활용법이 유사합니다.

차근차근 살펴보시고, 또 질문 남겨주세요.

화이팅입니다. :-)

isecure님의 프로필

isecure

질문자

2023.06.02

그냥 APIView에서는 구현에 성공하기는 했는데 modelvewset으로도 해보고 싶어서 삽질중이긴 합니다.

어떻게 됐는지 정확히 이해도 못한거 같기두 하구요. 그냥 얼떨결에 된거 같아서...

여기서 질문이 create가 view쪽에 있어야 맞는건지 serializer에 있어야 맞는건지 정확한 답을 모르겠습니다.

ViewSet의 create 메서드는 POST 요청을 받았을 때, View 역할로서 호출되는 메서드입니다.

관련 코드 : https://github.com/encode/django-rest-framework/blob/3.14.0/rest_framework/generics.py#L190

그리고 Serializer의 create 메서드는 유효성 검사를 통과했을 때, 해당 시리얼라이저 필드에 대한 validated_data를 가지고, 데이터베이스에 저장하는 역할을 하는 것이구요.

View는 시리얼라이저에 맞게 데이터를 준비해서 넘겨주고, 그 처리결과를 받아서 응답을 하는 책임이 있는 것이구요.

시리얼라이저는 소속 필드들에 대한 유효성 검사 및, 소속 필드들에 한해서 저장의 책임을 가지고 있습니다.

서로의 책임의 한계를 나눠서 생각해보시면, 이해하시는 데에 보다 도움이 되시지 않으실까 싶습니다.

화이팅입니다. :-)