From과 Serializer 관점에서 DRF 비교
2022. 7. 13. 15:32ㆍ강의 정리/Django REST Framework
반응형
Serializer / ModelSeializer
데이터 변환 / 직렬화 지원
- querySet / Model객체 <-> Native Python 데이터타입, JSON/XML
Django의 Form / ModelForm과 유사
- 유효성 검사와 유효성 검사에 통과한 값들을 데이터베이스에 저장 시켜줌
- Serializer는 뷰 응답을 생성하는 데에 범용적이고 강력한 방법을 제공
- ModelSerializer는 Serializer 생성을 위한 Shortcut
특징 비교
Form / ModelForm
- HTML 입력폼을 위한 입력에 대한 유효성 검사
- 주로 Create / Update에 대한 처리에서 활용 → 장고 admin에서 활용
- CreateView / UpdateView CBV를 통한 뷰 처리 → 단일 뷰
Serializer / ModelSerializer
- 데이터 변환 및 직렬화 지원 (JSON포맷 등)
- 주로 JSON 포맷 (주된 Web API 포맷) 입력에 대한 유효성 검사
- List / Create 및 특정 Record(Resource)에 대한 Retrieve / Edit(update or partial_update) / Delete 등에서 활용
- APIView를 통한 뷰 처리 → 단일 뷰
- ViewSet을 통한 뷰 처리 → 2개 뷰 → 2개 URL 처리
주된 호출 주체 비교
Form / ModelForm
- 일반적으로 웹 브라우저 상에서
- HTML Form Submit (POST 요청)
- JavaScript에 의한 비동기 호출
- 물론 Android/iOS앱에 의한 요청/응답도 가능
- 모두 http(s) 프로토콜 요청 / 응답이기에
Serializer / ModelSerializer
- 다양한 Client에 대한 Data위주의 http(s)요청
- by: Web / Android / iOS 등
클래스 정의 비교
Form / ModelForm : Form은 html 폼을 효율적으로 처리하기 위한 목적을 가진다.
from django import forms
class PostForm(forms.Form):
email = forms.EmailField()
content = forms.CharField(**widget=forms.Textarea**)
created_at = forms.DateTimeField()
class PostModelForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
Serializer / ModelSerializer : Serializer는 다양한 http 클라이언트로부터의 API 요청을 처리하기 위한 목적을 갖기에, widget과 같은 인자는 없다.
from rest_framework import serializers
# 시리얼라이저/디시리얼라이저 되어야 하는 필드 정의 필요
# create(), update() 메소드 정의 필요
# create(): 시리얼라이저를 대상으로 save() 메소드를 호출하여 DB 인스턴스를 생성할 때의 동작 정의
# update(): 시리얼라이저를 대상으로 save() 메소드를 호출하여 DB 인스턴스를 수정하고자 할 때의 동작 정의
class PostSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created_at = serializers.DateTimeField()
# Model과 필드를 정의
class PostModelSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
FBV를 통한 요청 / 응답 비교 – Form vs Serializer
Form
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save()
return redirect(post)
else:
form = PostForm()
return render(request, 'myapp/post_form.html', {
'form': form,
})
def post_list_or_create(request):
# 새 글 저장을 구현
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save()
# 커스텀 직렬화 루틴이 필요
return JsonResponse(post)
return JsonResponse(form.errors)
# 목록 응답을 구현
else:
qs = Post.objects.all()
return JsonResponse(qs) # 커스텀 직렬화 루틴이 필요
Serializer
def post_list_or_create(request):
if request.method == 'POST':
serializer = PostSerializer(data=request.POST)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
else:
qs = Post.objects.all()
serializer = PostSerializer(qs, many=True)
return Response(serializer.data)
from rest_framework.response import Response
from rest_framework.views import APIView
class PostListCreateAPIView(APIView):
def get(self, request):
serializer = PostSerializer(Post.objects.all(), many=True)
return Response(serializer.data)
def post(self, request):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
CBV를 통한 요청 / 응답 비교 – Form vs Serializer
장고 기본
from django.views.generic import ListView, CreateView
post_list = ListView.as_view(model=Post)
post_new = CreateView.as_view(model=Post, form_class=PostModelForm)
# 앱/urls.py
urlpatterns = [
path('', post_list),
path('new/', post_new),
]
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" />
</form>
DRF의 APIView
from rest_framework.generics import ListCreateAPIView
class PostListCreateAPIView(ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostModelSerializer
post_list_create = PostListCreateAPIView.as_view()
# 앱/urls.py
urlpatterns = [
# 단일 URL에서 list/create 요청 처리
path('api/post/', post_list_create),
]
유효성 검사 수행 시점 – Form vs Serializer
Form
class ProcessFormView(View):
def get(self, request, *args, **kwargs):
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
form = self.get_form() # POST 데이터를 통해 Form 객체 생성
if form.is_valid(): # 유효성 검사를 수행. 실패하면 False를 반환
return self.form_valid(form) # DB로의 저장을 수행
else:
return self.form_invalid(form) # 오류 HTML 응답
Serializer
# rest_framework/mixins.py
class CreateModelMixin(object):
def create(self, request, *args, **kwargs): # POST 요청 -> CREATE 요청이 들어오면,
serializer = self.get_serializer(data=request.data) # POST데이터를 통해 Serializer 인스턴스를 만들고
serializer.is_valid(raise_exception=True) # 유효성 검사를 수행. 실패하면 예외발생 !!!
self.perform_create(serializer) # DB로의 저장을 수행
headers = self.get_success_headers(serializer.data) # 필요한 헤더를 뽑고
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) # 응답을 합니다.
def perform_create(self, serializer): # CREATE 커스텀은 이 함수를 재정의하세요.
serializer.save()
커스텀 유효성 검사 루틴 - clean_* vs validate_*
Form -> clean_
from django import forms
class PostForm(forms.Form):
title = forms.CharField()
def clean_title(self):
value = self.cleaned_data.get('title', '')
if 'django' not in value:
raise forms.ValidationError('제목에 필히 django가 포함되어야 합니다.')
return value
Serializer -> validate_
from rest_framework.exceptions import ValidationError
class PostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
def validate_title(self, value):
if 'django' not in value:
raise ValidationError('제목에 필히 django가 포함되어야 합니다.')
return value
반응형
'강의 정리 > Django REST Framework' 카테고리의 다른 글
DRF Authentication과 Permission (0) | 2022.07.14 |
---|---|
DRF Serializer를 통한 유효성 검사 및 저장 (0) | 2022.07.14 |
DRF ViewSet과 Router (0) | 2022.07.13 |
DRF mixins 상속을 통한 APIView (0) | 2022.07.12 |
DRF로 APIView, Json 응답뷰 만들기 (0) | 2022.07.11 |