장고 - Rest Framework 사용
- 이번 포스트에서는 프론트엔드 개발자와 백엔드 개발자 간 협업을 위해 사용되는 REST API의 정의와 API를 생성하기 위한 Rest Framework 사용 방법에 대해 알아볼 것이다.
REST API란?
- REST(Representational State Transfer)
- 웹에 존재하는 모든 자원(이미지, 동영상, DB 자원)에 고유한 URI를 부여해 활용하는 것
- 자원(Resource) - URI
- 행위(Verb) - HTTP METHOD
- 표현(Representations)
- API(Application Programming Interface)
- 컴퓨터 프로그램 간 상호작용을 촉진하며, 서로 정보를 교환할 수 있도록 도와주는 것
- REST API
- 웹에 존재하는 모든 자원에 고유한 URI를 부여해 활용 가능한 API를 제공하는 것
- 백엔드 개발자와 프론트엔드, iOS, Android 개발자와의 협업을 위해 데이터 정보 교환이 가능하다.
Django Rest Framework 사용 방법
ex) dstagram_project
1. rest framework와 Swagger 설치
- django-rest-framework 설치
$ pip install djangorestframework
- Swagger 설치
$ pip install django-rest-swagger==2.1.2
2. INSTALLED_APP에 REST API 관련 기능 추가
- 경로 : config(프로젝트) > settings.py
1
2
3
4
5
6
7
8
9
10INSTALLED_APPS = [
...
'rest_framework',
# swagger UI 제공
'rest_framework_swagger',
# 토큰 제공
'rest_framework.authtoken',
# 특정 필드 서치 기능 제공
'django_filters',
]
3. API 동작을 위한 Serializers 생성
- 경로 : photo > serializers.py
1
2
3
4
5
6
7
8
9
10
11
12
13from rest_framework import serializers
from .models import Photo
class PhotoListSerializers(serializers.ModelSerializer):
class Meta:
model = Photo
fields = '__all__'
class PhotoSerializers(serializers.ModelSerializer):
class Meta:
model = Photo
fields = '__all__'
4. 인증 권한 부여 방법 설정
- 경로 : photo > permissions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from rest_framework import permissions
# 요청한 클라이언트가 해당 객체(포스트)의 생성자인 경우 인증 권한 부여
class IsOwnerOnly(permissions.BasePermission):
def has_object_permmission(self, request, view, obj):
return obj.author == request.user
# 요청한 클라이언트가 해당 객체(포스트)의 생성자이거나, 관리자인 경우 인증 권한 부여
class IsOwnerAndAdminOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.author == request.user or request.user.is_superuser
# 모두에게 읽기 권한 부여하, 요청한 클라이언트가 해당 객체(포스트)의 생성자이거나, 관리자인 경우 인증 권한 부여
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# 읽기 권한은 모두에게 허용
# GET, HEAD, OPTIONS 요청은 항상 허용
if request.method in permissions.SAFE_METHODS:
return True
# 쓰기 권한은 해당 객체의 소유자 혹은 관리장에게만 부여
return obj.author == request.user or request.user.is_superuser
5. settings.py에 기본 인증 방식, 토큰 방식, 서치 기능 추가
- 경로 : config > settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28REST_FRAMEWORK = {
# 로그인해야 모든 API 실행 가능
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
# 토큰 인증 방식 추가
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
# 서치 기능 추가
'DEFAULT_FILTER_BACKENDS': (
# 필터 가능
'django_filters.rest_framework.DjangoFilterBackend',
# 검색 필드 적용하여 ForeignKey로 묶인 필드들을 기준으로 검색 가능
# SearchField를 필터 백엔드에 추가
'rest_framework.filters.SearchFilter',
),
}
# Swagger에 Token 인증 방법 추가
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
"api_key": {
"type":"apiKey",
"name":"Authorization",
"in":"header",
}
}
}
6. generic 이용하여 뷰 작성
- 경로 : photo > views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27from rest_framework import generics
from .serializers import *
from .permissions import *
# list, create 기능을 하나의 클래스로 정의
class PhotoListView(generics.ListCreateAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoListSerializers
# ForeignKey로 연결된 필드의 키워드 서치
search_fields = ('text','author__username')
# create 시, 요청한 클라이언트를 요청한 데이터의 author로 설정
def create(self, request, *args, **kwargs):
request.data['author'] = request.user.id
return super().create(request, *args, **kwargs)
# 기본적으로 모든 API 뷰가 로그인해야만 실행될 수 있도록 하는 IsAuthenticated 호출
from rest_framework.permissions import IsAuthenticated
# detail, update, delete 기능을 하나의 클래스로 정의
class PhotoDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Photo.objects.all()
serializer_class = PhotoSerializers
# 로그인 이후 모든 API 뷰가 실행하도록 하고, 요청하는 클라이언트가 객체 생성자 혹은 관리자일 경우에 인증 권한 부여
permission_classes = [IsAuthenticated, IsOwnerAndAdminOnly]
7. API 뷰의 경로 설정
경로 : photo > urls.py
1
2
3
4
5
6
7from django.urls import path
urlpatterns = [
...
path('api_list/', PhotoListView.as_view()),
path('api_detail/<int:pk>/', PhotoDetailView.as_view()),
]경로 : config > urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from django.contrib import admin
from django.urls import include, path
from rest_framework_swagger.views import get_swagger_view
from rest_framework.authtoken.views import obtain_auth_token
schema_view = get_swagger_view(title='Dstagram API')
urlpatterns = [
...
# swagger UI 페이지 이동 위한 경로 설정
path('api/doc/', schema_view),
# 토큰 부여받기 위한 경로 설정
path('api/get_token/', obtain_auth_token),
]
8. accounts 앱에 serializers.py 생성
- 경로 : accounts > serializers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46from rest_framework import serializers
from django.contrib.auth import get_user_model
User = get_user_model()
# 유저 목록에 출력될 형식
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'first_name', 'last_name', 'email']
# 회원 가입할 때 필요한 필드들에 관한 serializer
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'password', 'first_name', 'last_name', 'email']
# 비밀번호 암호화(해쉬함수)하여 설정할 수 있도록 해주는 함수
def create(self, validated_data):
user = User.objects.create(**validated_data)
user.set_password(validated_data.get('password'))
user.save()
# create view 는 항상 생성한 객체 반환
return user
class UserModifySerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['password', 'first_name', 'last_name', 'email']
def update(self, instance, validated_data):
for key, value in validated_data.items():
if value:
setattr(instance, key, value)
if key == 'password' and value:
instance.set_password(value)
elif value:
setattr(instance, key, value)
instance.save()
return instance
class UserDetailSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password', 'first_name', 'last_name', 'email', 'is_superuser']
9. serializer를 활용한 뷰 작성
- 경로 : accounts > views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32from .serializers import UserListSerializer, UserCreateSerializer, UserModifySerializer, UserDetailSerializer
from rest_framework import generics
from rest_framework.permissions import AllowAny
class UserListAPI(generics.ListAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserListSerializer
# 원하는 검색 항목 추가
filterset_fields = ('username', 'first_name')
# 관리자의 경우에만 전체 목록 반환하고, 아닌 경우에는 자신의 정보만 반환
def get_queryset(self):
queryset = super().get_queryset()
if not self.request.user.is_staff:
queryset = queryset.filter(pk=self.request.user.id)
return queryset
# 인증 없이도 사용할 수 있도록 AllowAny 설정(회원가입 뷰 등)
class UserCreateAPI(generics.CreateAPIView):
serializer_class = UserCreateSerializer
permission_classes = [AllowAny]
class UserUpdateAPI(generics.UpdateAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserModifySerializer
class UserDetailAPI(generics.RetrieveAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserDetailSerializer
class UserDeleteAPI(generics.DestroyAPIView):
queryset = get_user_model().objects.all()
10. 뷰에 대한 경로 설정
- 경로 : accounts > urls.py
1
2
3
4
5
6
7
8
9
10
11
12from django.urls import path
from .views import *
app_name = "accounts"
urlpatterns = [
...
path('create/', UserCreateAPI.as_view()),
path('list/', UserListAPI.as_view()),
path('detail/<int:pk>/', UserUpdateAPI.as_view()),
path('delete/<int:pk>/', UserDeleteAPI.as_view()),
]
추가) Swagger UI 접속하여 데이터 정보 확인(DEBUG 모드일 경우)
- 127.0.0.1:8000/api/doc 접속
- api > /api/get_token/
- username, password 입력하여 token 확인
- 우측 상단 ‘Authorize’ 버튼 클릭
- value 값에 ‘Token [token 번호]’ 입력
- 필요한 데이터 확인
추가) postman 프로그램으로 데이터 정보 확인 (DEBUG 모드일 경우)
- postman 프로그램 이용하여 회원 정보 저장 및 데이터 확인
- token 받아오기
- 메인 화면에서 POST 선택 > 127.0.0.1:8000/api/get_token/ 입력 > Body 선택
- KEY 값에 ‘username’, ‘password’ 입력하고, VALUE 값에 해당 회원정보 입력
- SEND
- token 번호 확인
- 특정 데이터 정보 받아오기
- Swagger에서 받아오고 싶은 데이터 파악
- postman 실행
- 메인화면에서 GET 선택 > 127.0.0.1:8000/accounts/list 입력 > Headers 선택
- KEY 값에 ‘Authorization’ 입력하고, VALUE 값에 ‘Token [token 번호]’ 입력
- SEND
- 데이터 확인
- token 받아오기
Posted