본문 바로가기

Web Development/Django

[Django] Rest framework 개념 및 사용법(django-rest-framework)

728x90

RESTful이란?

RESTful이란, Representational State Transfer의 줄임말로서, http의 url과 http method(GET, POST, PUT, DELETE)를 사용해서 API 가독성을 높인 구조화된 시스템 아키텍쳐이며, 하나의 URL로 최소 4가지의 HTTP method를 전송할 수 있다는 장점이 있다. 

기존에는 웹 페이지를 보여주는 웹서버만 구현하여 웹 서버에서 DB서버의 데이터도 읽어오고, 사용자들이 글을 남기면 DB 서버에 저장까지 하는 기능을 모두 담당했다. 하지만 스마트폰이 출시되고, 어플리케이션의 등장으로 더이상 웹으로만 서비스를 제공하는 것에 한계가 있었다.

스마트폰 어플과 웹에서 동일한 기능을 제공하는데 기존의 웹서버를 계속 사용하면 매번 HTML을 읽어서 해당 태그에 있는 정보를 찾아내는 일을 반복해야 하기 때문이다. 따라서 HTML로 렌더링 하는 웹서버가 아닌, JSON 혹은 XML 과 같은 형식을 통해서 데이터를 다루는 별도의 API 서버가 필요했다. 

이때, RESTful 아키텍쳐를 HTTP Method와 함께 사용하면 웹, 데스크탑 앱, 스마트폰 어플들까지 하나의 API 서버(RESTful API)를 생성해 사용할 수 있다. RESTful API는 웹 서비스를 통해 통신하는 두 시스템 간의 변환기 역할을 하며, 다양한 장치에서 해석 할 수있는 JSON 파일을 반환한다.

django-rest-frame란?

Django 안에서 RESTful API 서버를 쉽게 구축할 수 있도록 도와주는 오픈소스 라이브러리

라우터, 인증/권한, 데이터 규격화 (시리얼라이저), 필터/페이지네이션, 캐시, 쓰로틀, 렌더러, 테스트 등의 기능을 제공하며, 대체로 django 에서 제공하는 기능을 감싼 wrapper 형태로 되어있다.
규약(convention)이 많지만, 웬만한 것들은 설정(configuration)을 통해 원하는 형태로 구현할 수 있습니다. 규약과 규약에서 제공하는 설정 가능성을 존중하는 범주 안에서는 엄청난 생산성 레버리지 효과를 누릴 수 있으며, 필요하다면 그런 이점을 포기하고 프로젝트에서 요구하는 형태로 기능을 구현할 수도 있습니다.

 

Django REST framework를 사용하는 이유는 아래와 같다.

  • 웹 브라우저 API는 범용성이 크다. 개발을 쉽게 만들어준다.
  • 인증 정책에 OAuth1, OAuth2 를 위한 추가적인 패키지가 추가되어 있는 경우
  • 시리얼라이즈 기능을 제공해준다. (DB data -> JSON)
  • 문서화 및 커뮤니티 지원이 잘 되어있다.

Serializer : 직렬화

기존 Django를 이용한 웹 개발에서 Django ORM의 Queryset은 Django template로 넘겨지며 HTML로 렌더링되어 Response로 보내지게 된다. 

하지만 JSON으로 데이터를 보내야 하는 RESTful API는 HTML로 렌더링 되는 Django template를 사용할 수 없습니다. 그래서 Queryset을 Nested한 JSON으로 매핑하는 과정을 거쳐야 하는데, 이 작업을 지금 작성할 Serializer이 하게 됩니다.

Serializer를 통해 queryset과 모델 인스턴스와 같은 복잡한 데이터를 json,xml 또는 다른 콘텐츠 유형으로 쉽게 변환할 수 있다. 받은 데이터의 유효성을 검사한 다음, 복잡한 타입으로 형 변환할 수 있도록 serialization을 제공한다. 

직렬화(serialization)를 하는 이유 Object는 메모리에 존재하고, 추상적인데 비해서 String or bytes 데이터는 드라이브에 저장 할 수 있고, 통신선으로 전송도 가능하다는 장점이 있기 때문이다. 

Serializer 적용 유무에 따른 데이터 타입 차이

  • 직렬화(serialization) : 추상적인 object를 구체적이고, 저장가능하고, 전송가능한 텍스트파일 (연속된 byte파일 = stream of bytes)로 바꿔주는 것
  • 역직렬화(deserialization) : 텍스트파일(연속된 byte 파일 = stream of bytes)를 직렬화된 데이터 포맷형태로 추상적인 object 데이터로 바꿔주는 것
  • 직렬화 할때의 데이터 포맷 형태를 알고있어야만 역직렬화 할때 똑같은 데이터포맷으로 역직렬화 시킬 수 있다
  • JSON, XML, YAML 과 같은 문서 포맷이 주로 직렬화의 대상이 된다
  • IP, TCP, UDP는 네트워크로 통신하는 메시지들은 데이터 타입이나 데이터 포맷을 알수 없다

예를 들어, 단순 Django 프로젝트에서는 return JSONResponse 를 이용해서 JSON 형태를 취해서 데이터를 전송했다. 하지만 DRF를 사용하면 JSON 형태로 만들어서 보내주기때문에 JSONResponse 를 사용하지 않아도 된다. 

 

서버와 web-browser 에서 데이터를 주고 받을때,
1. object에서 json 파일로 직렬화 해서 전송을 하고
2. 다운로드 받은 것은 json 파일을 역직렬화해서 object를 복구한다.

Serialization/ Deserialization 과정

Serializing Objects

# models.py
from django.db import models

class Comment(models.Model):
	email = EmailField()
    content = CharField(max_length=1000)
    created = DateTimeField()
    
from rest_framework import serializers

# serializers.py
class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

>> serializer = CommentSerializer(comment)
>> serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

 

python datatype에서 JSON으로 출력하기 위해서는 아래와 같이 랜더링을 거쳐야된다.

 

from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

Deserializing objects

import io
from rest_framework.parsers import JSONParser

stream = io.BytesIO(json)
data = JSONParser().parse(stream)

serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
  • deserializing 한 데이터는 항상 is_valid() 함수를 호출해야됨

Saving instances

# serializers.py
# 생략..
def create(self, validated_data):
        return Comment.objects.create(**validated_data)

def update(self, instance, validated_data):
      instance.email = validated_data.get('email', instance.email)
      instance.content = validated_data.get('content', instance.content)
      instance.created = validated_data.get('created', instance.created)
      instance.save()
      return instance

# views.py
comment = serializer.save()

# .save() will create a new instance.
serializer = CommentSerializer(data=data)

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)

serializer.is_valid()
>> False
serializer.errors
  • model에 저장하기위해서 create or update 둘 중하나의 메소드를 사용하여 저장한다.
  • serializer에 instance를 전달하면 update를 실행하고, instance를 전달하지 않으면 create를 실행한다.

ModelSerializer

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']

# '__all__' attribute 이용
class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'
  • 모델에 따라 자동으로 필드 세트가 생성된다
  • serializer에 대한 유효성 검사기를 자동으로 생성한다.
  • create(),update() 의 간단한 기본 구현이 포함되어 있다.

 

View

rest_framework 의 API View 는 크게 두가지, CBV(Class Based View) 와 FBV(Function Based View) 로 구분 할 수 있다. 

CBV는 Class 의 장점을 모두 사용할 수 있어 코드의 효율을 극대화 할 수 있는 장점이 있고, 여러가지 조건들에 맞게 API 를 개발할 시, 중복되는 코드의 길이를 줄여 효율을 높일 수 있는 등의 장점이 있다.

permission_classes는 API의 접근 권한을 지정한다. 모든 사람이 접근가능한 AllowAny, authentication_classes에 의해 인증이 완료된 사용자만 접근 가능한 IsAuthenticated, admin 사용자일 때만 접근이 가능한 IsAdminUser 등을 사용할 수 있다.

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        # 'rest_framework.permissions.IsAdminUser',
    ],
}

renderer_classes는 사용자에게 응답이 전송될때 어떤 렌더링을 사용할지 설정한다. 페이타임은 기본적 JSON을 통신 규약으로 설정하고 있기 때문에 사용자 정보를 JSON 형태로 렌더링할 수 있도록 하는 설정이다.

authentication_classes는 permission_classes가 IsAuthenticated로 설정되었을때 필요한 역할을 한다. 해당 클래스에서는 현재 요청을 보낸 사용자가 인증된 사용자인지 아닌지를 나타내서 접근 권한을 책임진다.

추후 포스팅에서 Custom authentication_class를 구성하는 방법을 다룰 예정이다. 기본적으로 DRF에서 제공하는 클래스들이 있지만, 각 서비스에서 원하는 인증 클래스가 여러가지가 있을 수 있다. 예를 들면, 폰을 인증한 사용자만 접근이 가능하도록 하는 인증 클래스가 필요할 것이고,  폰 인증을 하진 않았지만 로그인된 사용자가 접근 가능한 인증 클래스가 있을 수 있기 때문에 자신의 입맛에 맞는 인증 클래스를 구성하는 방법이 필요하다.

 

 

DRF (Django Rest Framework) 설치

pip install djangorestframework

사용법

 

settings.py의 INSTALLED_APPS에 rest_framework를 추가한다

# settings.py

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    ...
    'rest_framework',
    ...
]

6. Model 생성

# movie_api/movies/models.py

from django.db import models

class Movie(models.Model):
    title = models.CharField(max_length=30) # 제목
    genre = models.CharField(max_length=15) # 장르
    year = models.IntegerField() # 제작 년도

    def __str__(self):
        return self.title

코드 작성 후 migration 진행

python manage.py makemigrations
python manage.py migrate

 

7. Model을 serialize하는 serializer.py 작성

 

# movie_api/movies/serializers.py

from rest_framework import serializers
from .models import Movie

class MovieSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie # 모델 설정
        fields = ('id','title','genre','year') # 필드 설정

8. views.py 작성

DRF는 보통 사람들이 자주 사용하는 공통적인 view 로직을 그룹화 한 viewset을 제공한다. viewset을 사용하게 되면 CRUD 로직을 직접 짜지 않아도 이 기능들이 사용 가능해진다. 필자는 처음에 '읭 아무것도 안했는데 다 되네...? ㅇ0ㅇ' 했다.

# movie_api/movies/views.py

from rest_framework import viewsets
from .serializers import MovieSerializer
from .models import Movie

class MovieViewSet(viewsets.ModelViewSet):
    queryset = Movie.objects.all()
    serializer_class = MovieSerializer

9. urls.py 작성

DRF는 url을 자동으로 맵핑해주는 router를 제공한다. 앞서 생성한 viewset을 router에 연결하게 되면 자동으로 url을 맵핑해주어 사용자가 직접 url을 맵핑하지 않아도 된다.

# movie_api/urls.py

from django.conf.urls import url,include
from django.contrib import admin
from rest_framework import routers
from movies.views import MovieViewSet

router = routers.DefaultRouter() 
router.register('movies',MovieViewSet) # prefix = movies , viewset = MovieViewSet

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^',include(router.urls)),
]

위에서 router.register로  prefix를 'movies'로 설정을 해주었다. 

router는 이를 바탕으로 url을 맵핑하게 된다.

URL pattern: ^movies/$ Name: 'movie-list'
URL pattern: ^movies/{pk}/$ Name: 'movie-detail'

10. 실행

자 이제 코드 작성은 끝이 났다! 런서버로 실행해본다. 

python manage.py runserver 


Reference

 

django rest framework 시작하기 - 1

django rest framework 시작하기, 길어질 연재의 첫번째 글입니다. 어떤 상황에서 어떤 기능들을 활용해 생산성을 더 끌어올릴 수 있는지, 그 외의 여러 기술적인 고민까지 두루 다뤄볼 예정입니다.

velog.io

 

django REST framework로 간단한 api 만들기

django REST ramework (DRF)는 RESTful한 API를 쉽게 만들 수 있도록 해준다.  지금부터 DRF를 사용해 영화 리스트를 CRUD (Create,Read,Update,Delete) 할 수 있는 간단한 API를 만들어 볼 것이다. 혹시 REST..

jamanbbo.tistory.com

 

 

반응형