DRF 구현
💡 Django 기본 구현 vs DRF 구현
오늘은 Django 기본구현과 DRF구현의 차이점에 대해서 공부했다.
처음에 instagram에서 Post모델에 대한 API를 설계할 때 아래와 같이 했었다.
1. 새 포스팅 내용을 받아 등록하고,확인 ⇨ /post/new/ ; POST요청
2. 포스팅 목록 및 검색 응답 ⇨ /post/ ; GET요청
3. 1번 포스팅 내용 응답 ⇨ /post/1/ ; GET요청
4. 1번 포스팅 내용 갱신하고, 확인 응답 ⇨ /post/1/update ; POST요청
5. 1번 포스팅 내용 삭세하고, 확인 응답 ⇨ /post/1/delete ; POST요청
REST API 스타일로 재설계를 해본다면 아래와 같다.
1. /post/주소
GET 방식 요청 : 목록 응답
POST 방식 요청 : 새 글을 생성하고 , 확인 응답
2. /post/10/주소
GET 방식 요청 : 10번 글 내용 응답
PUT 방식 요청 : 10번 글 내용 수정/저장, 확인 응답
DELETE 방식 요청 : 10번 글 삭제, 확인 응답
# models.py
class Post(models.Model):
message = models.TextField()
# froms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
# views.py
def post_list(request):
if request.method == "POST":
# 새 글 저장을 위한 구현
form = PostForm(request.POST, request.FILES)
if form.is_valid:
post = form.save()
return JsonResponse(post)
else:
return JsonResponse(form.errors)
else:
# 목록 응답을 위한 구현(GET)
return JsonResponse(Post.objects.all())
def post_detail(request):
post_detail = Post.get_object_or_404(Post,pk=pk)
if request.method == "PUT":
# 특정 글 갱신을 구현
put_data = Querydict(request.body)
form = PostForm(put_data, instance=post)
if form.is_valid:
post = form.save()
return JsonResponse(post)
else:
return JsonResponse(form.errors)
elif request.method == "DELETE":
# 특정 글 삭제를 구현
post.delete()
return HttpResponse()
else:
# 특정 글 내용 응답을 구현
return JsonResponse(post)
위의 코드를 다른 모델에 대해서 동일한 기능을 구현한다면,
Model/Form을 제외하고는 거의 정형화된 패턴을 보여준다.
DRF는 이런 정형화된 중복을 줄일 수 있도록 도와주는 CBV를 비롯하여
다양한 기능을 지원해준다.
위의 코드를 DRF를 기반으로 다시 작성하기 전에 djangorestframework 설치를 해줘야 한다.
pip install djangorestframework
설치를 완료 했으면 settings.INSTALLED_APPS
에 rest_framework
를 추가한다.
그리고 urlpatterns에 다음 패턴을 추가해준다.
# 프로젝트명/urls.py
urlpatterns = [
path('api-auth', include('rest_framework.urls')
]
여기서 include 안에 있는 rest_framework는 단순히 django.contrib.auth의
login, logout을 활용한 것이다.
from django.conf.urls import url
from django.contrib.auth import views
app_name = 'rest_framework'
urlpatterns = [
url(r'^login/$', views.LoginView.as_view(template_name='rest_framework/login.html'), name='login'),
url(r'^logout/$', views.LogoutView.as_view(), name='logout'),
]
이제 DRF로 Post모델에 대한 API를 설계해보면, 아래와 같이 할 수 있다.
# models.py
class Post(models.Model):
message = models.TextField()
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = '__all__'
# views.py
from rest_framework import viewsets
from .seliarlizer import PostSerializer
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
# urls.py
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
# 2개의 URL을 만들어 준다.
# 생성된 "2개의 URL"은 router.urls에 list형태로 존재한다.
router.register('posts', views.PostViewSet)
urlaptterns = [
path('', include(routers.urls)),
]
굉장히 코드가 간결해졌다.
Form/ModelForm → Serializer/ModelSerializer
FBV/CBV → FBV/CBV 그리고 ViewSet/ModelViewSet 등
그리고 ursl.py 부분이 이해가 잘 안되서
router.urls를 출력해 봤더니 출력 결과는 아래와 같았다.
[
<URLPattern '^post/$' [name='post-list']>,
<URLPattern '^post\.(?P<format>[a-z0-9]+)/?$' [name='post-list']>,
<URLPattern '^post/(?P<pk>[^/.]+)/$' [name='post-detail']>,
<URLPattern '^post/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='post-detail']>,
<URLPattern '^$' [name='api-root']>,
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
]