본문 바로가기
관리자

Programming-[Backend]/Django

[TIL] Django ListSerializer 활용, List Update/Create

728x90
반응형

 

 

viewset을 이용하면 list, create API 끼리 묶이고, retrieve, update, destroy 끼리 detail로 묶여서 동작한다. 여기서 detail쪽은 반드시 어떤 테이블의 레코드와 일치하는 특정 인스턴스를 가리키기 위해서 아래와 같이 pk 값을 써줘야한다.

 

특정 학생 정보를 업데이트하기 위해 student의 pk값을 받는다.

https://django.school/<int:school_id>/student/<int:pk>

 

그래서 만약 여러 레코드(인스턴스)를 한 번에 update하고 싶다면 ListSerializer를 구성하여 처리해야한다.

 

 

 

Serialier 구성

 

class StudentListSerializer(serializers.ListSerializer):

    def update(self, instance: List[Student],
               validated_data: OrderedDict):
        original_student_mapping = {original.id: original for original in instance}
        request_body_mapping = {student["id"]: student for student in validated_data}

        updated_students = self.update_students(original_student_mapping, request_body_mapping)

    #...중략
    
    #sudo code
    self.child.update(original_student, request_body)


class StudentSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    age = serializer.IntegerField()
    major = serializer.CharField()

    class Meta:
        model = AnnotationPosition
        fields = ["id", "age", "major"]
        list_serializer_class = StudentListSerializer

 

개별 StudentSerializer를 구성한 뒤, Meta 정보에 list_serializer_class를 지정해주었다.

ListSerializer를 구성한 뒤, 각 요소를 child 로 불러와서 업데이트하였다.

 

 

ViewSet 구성

 

class StudentViewSet(
    viewsets.ModelViewSet
):
    serializer_class = StudentSerializer

	# 중략...


    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', True)
        instances = self.get_queryset()
        serializer = self.get_serializer(instances, many=True, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        return Response(serializer.data)

 

단일 인스턴스에 대한 Serializer를 serializer_class로 지정하고, get_serializer method에서 instances로 여러 객체를 전달, many=True값을 주어야한다.

 

request body 포맷

상기 내용대로 하면 요청 바디를 List 형태로 보내줘야한다.

[
    {
        "id": 1,
        "age": 23
        "major": "MECHANICAL_ENGINEERING"
    },
    {
        "id": 2,
        "age": 24
        "major": "COMPUTER_SCIENCE"
    },
    ...
]

 

만약 이 형태가 불편하다면, get_serializer에서 데이터를 던져줄 때 request.data가 아니라 객체 이름으로 찾은 list를 전달해주면 된다.

 

{"students": [
    {
        "id": 1,
        "age": 23
        "major": "MECHANICAL_ENGINEERING"
    },
    {
        "id": 2,
        "age": 24
        "major": "COMPUTER_SCIENCE"
    },
    ...
]
}

 

-> 

        serializer = self.get_serializer(instances, many=True, data=request.data["students"], partial=partial)

 

 

더 살펴보기

 

 

단순히 업데이트만 하는 것이 아니라 id 값을 비교하여 없으면 create를 할 수도 있다. 이런 복합 기능을 위해서는 주의해야할 사항들이 있으니, 아래 DRF 공식문서 내용을 참고하여 작성하면 될 것 같다.

 

ListSerializer 부분을 참고해야한다.

https://www.django-rest-framework.org/api-guide/serializers/#listserializer

728x90
반응형