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_APPSrest_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']>
]



📚 References