DRF를 사용해서 사용자를 관리하는 백엔드 앱을 만드는 간단한 프로젝트를 진행중이다.
지금까지는 DRF가 아닌 Native한 Django만을 사용해서 백엔드 앱을 만들어왔었는데, DRF를 얕게나마 경험을 해보니 장단점이 느껴지는 것 같다.
DRF도 그렇고, Django도 그렇고 지금 내 이해도가 높은 수준은 아니지만 일단 어느정도 예제를 수행해보고 내 나름의 설계에 따른 앱을 만드는 과정에 있어서 가장 큰 차이점은 Serializer와 viewset, router 정도가 있을 것 같다. 아직 직접적으로 사용해보진 않았지만, Django에서는 관련 데코레이터를 직접 구현해서 사용해야했던 권한 관리나, 페이지네이션 기능도 DRF에 포함되어 있어서 가져다 사용할 수 있는 것 같다.
일단 가장 빨리 접했던 차이점인 Serializer에 대해서 간단하게 정리해보고, 어떻게 진행해야 하는지 조금 애먹었던 복잡한 관계로 이루어진 모델에 대한 Serializer 사용법을 정리해보려고 한다.
Serializer?
나는 Serializer가 일종의 관문같은 역할을 하는 요소라고 이해하고 있다. 프론트엔드 - 백엔드 간의 API통신에서 결국은 한정된 HTTP 메소드와 JSON 객체를 사용하게 되는데, 이중 JSON 객체에 대한 처리를 담당하는 요소이다. 직렬화라는 용어를 사용하여 Serializer가 하는 작업을 표현한다.
DB에서 데이터를 읽어낸 객체들의 Queryset이나, 프론트엔드에서 호출한 API에 대한 data에 작용할 수 있다.
- Serialize(직렬화) : 객체를 문자열 데이터로 변환하는 과정
- De-Serialize(역직렬화) : 문자열 데이터를 객체로 변환하는 과정
뭐가 좋을까?
일단 철저하게 내 기준에서 본다면 Serializer를 사용하지 않았던 이전에는 프론트엔드 개발자와 어떤 API를 호출하려면 어떤 형태의 data 파트의 JSON 객체 형태(Key의 이름, Value의 Type, 여러 데이터 등등)를 사용해야 하는지 결정하는 과정이 꼭 필요했다. 호출에 대한 Response의 형태 또한 동일한 과정이 필요했다. 협의 하는 과정 말고도 직접적인 코딩의 영역에서도 각각의 API들에 Response로 사전에 정한 형태로 구성하는 작업도 일일히 진행되어야 했었다.
그리고 API 호출에 있어서 필요한 Data가 전부 있는지 검증하는 과정에 대응하는 코드 역시 각 API마다 준비되었어야 했다.
Serializer를 사용하면 data의 형태를 결정하는 회의나 코딩 작업, 전달받은 data의 검증 같은 과정을 간단하게 처리할 수 있다.
먼저 data의 형태의 경우는 API호출의 경우에는 어쩔수 없지만, Response에 대해서는 일관된 형태로 구성할 수 있다.
# drf_prac/Serializers.py
class PracticeSerializer(serializers.ModelSerializer):
class Meta:
model = Practice
fields = ('__all__')
# drf_prac/views.py
@api_view(['GET', 'POST'])
def PracticeView(request):
if request.method == 'GET':
all_data = Practice.objects.all()
serializer_class = PracticeSerializer(all_data, many = True).data
return Response(serializer_class)
Django만 사용하던 시절이었으면 all() ORM 수행 이후에 위와 같은 형태의 리스트를 만들기 위한 리스트 컴프리핸션을 수행한 후에 해당 데이터를 JsonResponse를 통하여 프론트로 전달했을 것이다. 이미 만들어져서 내장된 기능을 가져다 사용하는 것에는 여러 장단점이 있겠지만 일단 확실한건 내 실수로 인해서 Response의 형태가 바뀔 일은 없다는 점이 좋은 것 같다.
다음으로 data의 검증 과정에 편리와 신뢰를 동시에 보장해준다.
create와 같은 동작에 사용되는 Serializer는 is_valid() 메소드를 호출하지 않으면 데이터를 직렬화된 데이터에 접근할 수 없다.
serializer 함수의 원형을 간단하게 살펴봤는데 데이터 검증 절차는 다음과 같은 순서로 이루어지는 것 같다.
- Serializer 객체를 생성하면서 API 호출시에 전달받은 data를 인자로 넘긴다.
- Serializer의 생성자로 전달받은 data를 생성된 객체의 '미검증 데이터'로 다룬다.
- is_valid() 메소드가 호출되면, '미검증 데이터'로 분류된 데이터가 먼저 선언된 Serializer의 필요 데이터를 포함하는 지 확인한 후 포함되면 해당 데이터들을 '검증 데이터(validated_data)'로 지정하고, True를 리턴. 만약 부족한 데이터가 있다면 False를 리턴한다.
# drf_prac/serializers.py
class WritePracticeSerializer(serializers.Serializer):
attr_1 = serializers.IntegerField()
attr_2 = serializers.IntegerField()
attr_3 = serializers.IntegerField()
def create(self, validated_data):
return Practice.objects.create(**validated_data)
# drf_prac/views.py
@api_view(['GET', 'POST'])
def PracticeView(request):
...
elif request.method == 'POST':
serializer_class = WritePracticeSerializer(data = request.data)
if serializer_class.is_valid():
serializer_class.save()
return Response(data = serializer_class.data, status = status.HTTP_200_OK)
else:
return Response(status = status.HTTP_400_BAD_REQUEST)
is_valid() 메소드를 호출하는 과정을 거치지 않으면 코드레벨에서 익셉션이 발생하기 때문에 신뢰성을 확보할 수 있고, 필요한 데이터가 전부 있는지 일일히 확인하고 그에 따른 Response를 지정해야 하는 수고를 덜어줄 수 있다.
단점은 없을까?
아직까지 명확하게 보이는 단점은 없어보인다. 그저 이미 있는 걸 사용하기보다는 직접 만들어서 사용하기를 좀 더 선호하는 개인적인 성격때문에 아직까지는 거부감이 조금 드는 편이다. 익숙해진다면 절대적인 코드량을 줄일 수 있을테니 작업 시간도 좀 더 효율적으로 관리 할 수 있을 것 같다.
다만 이런식의 프레임워크들의 공통적인 단점이라고 할 수 있는 부분은 있는 것 같다.
내가 알기로는 Django만 해도 굉장히 큰 프레임워크로 알고 있는데, 거기에 REST API 서버를 구축하기 위한 여러 도구들이 더해진게 DRF이다보니, 각각의 기능이 정확하게 어떻게 동작하는 지 파악하기 힘든 점이 있다. 이런 점들은 문제없을 때는 별 거 아니지만 문제가 생겼을 때, 문제가 생긴 원인과 지점을 명확하게 파악하는 과정을 조금 어렵게 할 수 있다고 생각한다.
사실 DRF를 완벽하게 이해하고 사용하면 별 문제 없을 것 같긴 하다.
'프로그래밍 > Python' 카테고리의 다른 글
Django - Admin(Search, Filtering) (0) | 2022.02.04 |
---|---|
Python - 예외처리 (0) | 2021.11.18 |
Django - Redis 캐싱 (0) | 2021.09.27 |
Django - 로깅 (0) | 2021.09.11 |
Conda 기본 (0) | 2020.07.29 |