serializer / ModelSerializer
데이터 변환/직렬화 지원
- QuerySet/Model객체 -> Native Python 데이터타입, JSON/XML 등
- Serializer는 뷰 응답을 생성하는 데에 범용적이고 강력한 방법을 제공
- ModelSerializer는 Serializer 생성을 위한 Shortcut
비교) Features
- HTML 입력폼을 통한 입력에 대한 유효성 검사
- 주로 Create/Update에 대한 처리에서 활용 -> 장고 admin 에서 활용
- CreateView/UpdateView CBV를 통한 뷰 처리 -> 단일 뷰
Serializer / ModelSerializer
- 데이터 변환 및 직렬화 지원 (JSON 포맷 등)
- 주로 JSON 포맷 (주된 Web API 포맷) 입력에 대한 유효성 검사
- List/Create 및 특정 Record에 대한 Retrieve/Edit/Delete 등 에서 활용
- APIView를 통한 뷰 처리 -> 단일 뷰
- ViewSet을 통한 뷰 처리 -> 2개 뷰 -> 2개 URL 처리
비교) 주된 호출 주체
일반적으로 웹브라우저 상에서
- HTML Form Submit
- JavaScript에 의한 비동기 호출
물론, Android/iOS 앱에 의한 요청/응답도 가능
- 모두 http(s) 프로토콜 요청/응답하기에.
Serializer
다양한 Client에 대한 Data 위주의 http(s) 요청
비교) 클래스 정의
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
from rest_framework import serializers
class PostSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created_at = serializers.DateTimeField()
class PostModelSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
비교) FBV를 통한 요청/응답
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)
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)
Serializer
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를 통한 요청 및 응답 (1)
장고 기본
from django.views.generic import ListView, CreateView
post_list = ListView.as_view(model=Post)
post_new = CreateView.as_view(model=Post, form_class=PostModelForm)
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>
비교) CBV를 통한 요청 및 응답 (2)
DRF의 APIView
from rest_framework.generics import ListCreateAPIView
class PostListCreateAPIView(ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostModelSerializer
post_list_create = PostListCreateAPIView.as_view()
urlpatterns = [
path('api/post/', post_list_create),
]
비교) CBV를 통한 요청 및 응답 (3)
- 참고) user_agent 필드는 요청 Header의 User-Agent 헤더를 활용하는 것이 좋습니다. -> request.META.get("HTTP_USER_AGENT")
유효성 검사 수행 시점
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()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
Serializer
class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
커스텀 유효성 검사 루틴
clean* vs validate*
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
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