[DRF] drf-writable-nested 사용 방법에 대한 정리
https://github.com/beda-software/drf-writable-nested
1. drf-writable-nested란?
1) 정리 :
- Django REST framework를 이용해 API를 개발할 때 중첩된(nested) 관계의 데이터를 쓰기 가능하게 만들어주는 라이브러리입니다. 즉, Serializer 내에서 관계된 객체를 생성, 업데이트, 삭제할 수 있는 기능을 제공하여 복잡한 데이터 구조를 편리하게 다룰 수 있도록 돕습니다. 이 라이브러리를 사용하면 중첩된 시리얼라이저를 통해 효율적으로 데이터를 다룰 수 있으며, 폼을 통한 다중 레벨 중첩 관계에서도 매끄러운 작업을 가능하게 해줍니다.
2) drf-writable-nested의 장점과 특징 :
- 읽기 및 쓰기가 가능한 중첩 작업 :
- 일반적으로 DRF에서 중첩 시리얼라이저는 읽기 전용이지만, drf-writable-nested는 중첩된 데이터 구조에서 생성 및 업데이트 작업을 할 수 있게 해줍니다.
- 관계 유지 :
- 다양한 유형의 관계(ForeignKey, ManyToManyField 등)를 지원하며, 중첩된 관계에서 원본 객체와 연관 객체 사이의 관계를 유지하면서 데이터 조작이 가능합니다.
- 복잡성 감소 :
- 클라이언트 측에서 받은 데이터 구조를 필요에 맞게 변환하지 않고도 직접적으로 모델에 적용할 수 있어서, 서버 측에서의 복잡성을 줄여주고 코드를 간결하게 만들 수 있습니다.
- 유효성 검사와 같은 기능 포함 :
- drf-writable-nested는 DRF의 기본 시리얼라이저처럼 유효성 검사 등을 포함하여 중첩된 데이터에 대한 오류 검출 및 처리를 용이하게 합니다.
- 기존 API 구조와의 통합 용이성 :
- 이미 구축된 API 구조에 중첩된 데이터 작업을 추가하기 위한 간단한 방법을 제공하여 기존 시스템과의 호환성을 높입니다.
3) 일반적인 제한 사항 :
- 상세한 유효성 검사 :
- drf-writable-nested는 기본적인 중첩 생성과 갱신을 지원하지만, 복잡한 유효성 검사나 커스텀 동작은 사용자가 직접 오버라이드해야 할 수 있습니다.
- 큰 변경에 따른 대응 :
- DRF나 다른 종속 패키지들의 큰 변경사항에 대해서는 drf-writable-nested가 신속하게 대응하지 못할 수 있으며, 이는 사용자에게 문제를 야기할 수 있습니다.
4) 구체적인 제한 사항 :
- validated_data와 initial_data :
- drf-writable-nested는 주로 initial_data를 참조하여 객체를 생성 및 갱신하기 때문에, validated_data를 기반으로 추가적인 처리를 하려 할 때 어려움이 발생할 수 있습니다.
- 트랜잭션 관리 :
- 복잡한 트랜잭션을 관리하는 경우, DRF의 기본 지원 기능만으로는 부족할 수 있으며, drf-writable-nested가 이를 모두 해결해주지는 않습니다.
- 많은 양의 자동화된 업데이트 지원 :
- 대량의 자동 업데이트 시나리오에서 drf-writable-nested의 지원은 제한적일 수 있습니다.
5) 오버라이딩 시 주의점 :
- 기본 메소드 오버라이딩 :
- 필요한 동작을 수행하기 위해서는 DRF 시리얼라이저에서 제공하는 create() 또는 update()와 같은 메소드를 사용자가 직접 오버라이드해야 하며, 이 과정에서 drf-writable-nested가 기대한 대로 작동하지 않을 수 있습니다.
2. 설치 방법 :
pip install drf-writable-nested
3. 기본 drf의 nested 구현
- 학교(School) 모델이 교사(Teacher)와 학생(Student)의 데이터를 포함하는 경우 중첩된 교사와 학생에 대한 데이터를 학교의 create와 update를 통해 nested serializer의 관련 입력을 관리해줘야 한다.
- 모델 설정 :
# models.py
from django.db import models
class School(models.Model):
name = models.CharField(max_length=100)
class Teacher(models.Model):
name = models.CharField(max_length=100)
school = models.ForeignKey(School, related_name='teachers', on_delete=models.CASCADE)
class Student(models.Model):
name = models.CharField(max_length=100)
school = models.ForeignKey(School, related_name='students', on_delete=models.CASCADE)
- 시리얼라이저 설정 :
# serializers.py
from rest_framework import serializers
from .models import School, Teacher, Student
class TeacherSerializer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = '__all__'
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = '__all__'
class SchoolSerializer(serializers.ModelSerializer):
teachers = TeacherSerializer(many=True)
students = StudentSerializer(many=True)
class Meta:
model = School
fields = '__all__'
def create(self, validated_data):
teachers_data = validated_data.pop('teachers')
students_data = validated_data.pop('students')
school = School.objects.create(**validated_data)
for teacher_data in teachers_data:
Teacher.objects.create(school=school, **teacher_data)
for student_data in students_data:
Student.objects.create(school=school, **student_data)
return school
def update(self, instance, validated_data):
# 이곳에 중첩된 관계의 인스턴스를 갱신하는 코드를 작성합니다.
# ...
return instance
- 뷰 설정 :
# views.py
from rest_framework import viewsets
from .models import School
from .serializers import SchoolSerializer
class SchoolViewSet(viewsets.ModelViewSet):
queryset = School.objects.all()
serializer_class = SchoolSerializer
4. drf-writable-nested를 이용한 nested 구현
- 이전 학교에서 관리했던 create, update를 직접 구현하지 않아도 제대로 동작을 한다.
- 모델 설정 :
# models.py
from django.db import models
class School(models.Model):
name = models.CharField(max_length=100)
class Teacher(models.Model):
name = models.CharField(max_length=100)
school = models.ForeignKey(School, related_name='teachers', on_delete=models.CASCADE)
classes_taught = models.ManyToManyField('Class', related_name='taught_by')
class Student(models.Model):
name = models.CharField(max_length=100)
school = models.ForeignKey(School, related_name='students', on_delete=models.CASCADE)
classes_attended = models.ManyToManyField('Class', related_name='attended_by')
class Class(models.Model):
subject = models.CharField(max_length=100)
- 시리얼라이저 설정 :
# serializers.py
from rest_framework import serializers
from drf_writable_nested import WritableNestedModelSerializer
from .models import School, Teacher, Student, Class
class ClassSerializer(serializers.ModelSerializer):
class Meta:
model = Class
fields = '__all__'
class TeacherSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
classes_taught = ClassSerializer(many=True)
class Meta:
model = Teacher
fields = '__all__'
class StudentSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
classes_attended = ClassSerializer(many=True)
class Meta:
model = Student
fields = '__all__'
class SchoolSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
teachers = TeacherSerializer(many=True)
students = StudentSerializer(many=True)
class Meta:
model = School
fields = '__all__'
- 뷰 설정 :
# views.py
from rest_framework import viewsets
from .models import School
from .serializers import SchoolSerializer
class SchoolViewSet(viewsets.ModelViewSet):
queryset = School.objects.all()
serializer_class = SchoolSerializer
- 결과
{
"name": "우리학교",
"teachers": [
{
"name": "김선생님",
"classes_taught": [
{"subject": "수학"},
{"subject": "과학"}
]
}
],
"students": [
{
"name": "홍길동",
"classes_attended": [
{"subject": "수학"},
{"subject": "영어"}
]
},
{
"name": "임꺽정",
"classes_attended": [
{"subject": "과학"},
{"subject": "영어"}
]
}
]
}
'Study > django' 카테고리의 다른 글
[DRF] FCM 관련 Django 라이브러리 정보 정리 (0) | 2024.03.09 |
---|---|
[DRF] Django with FCM - firebase push message 자료 정리 (0) | 2024.03.09 |
django orm deep dive 2 - Django 5 ORM Model Essentials 2024 (1) | 2024.03.07 |
django orm deep dive 1 - DJ101 | Django Database ORM Mastery Course (1) | 2024.03.06 |
[UDEMY]Django DRF Project: eCommerce RESTful API 강의 평가 (0) | 2024.03.01 |
댓글