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
'Programming-[Backend] > Django' 카테고리의 다른 글
[TIL] Django Restframework Exception Handler 개요 (0) | 2023.04.16 |
---|---|
[TIL] Django Cache 개요 (0) | 2023.04.16 |
[TIL] django, MYSQL, postgresql db collation (0) | 2023.02.15 |
[TIL] DjangoFilter(DRF filter_bakcends, django-filter filterset_class) (0) | 2023.01.16 |
[탐험] Django admin에서 view, template, render 다루기. 비동기 처리 버튼 만들기 (0) | 2022.12.25 |