http://www.yes24.com/Product/Goods/69758579
위 책을 참고하여 쓴 내용이다.
1. django 설치 및 프로젝트 생성하기
pip install django # conda install django
django-admin startproject config .
python manage.py migrate
python manage.py createsuperuser
2. 앱 만들고 INSTALLED_APPS에 등록
python manage.py startapp booking
3. 모델 만들고 데이터베이스에 적용
# booking/models.py
from django.db import models
from django.conf import settings
class Booking(models.Model):
subscriber = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name='bookings')
date_from = models.DateField()
date_to = models.DateField(null=True, blank=True)
room = models.CharField(max_length=100)
note = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.subscriber.username + " " + self.room
class Meta:
ordering = ['-date_from']
python manage.py makemigrations booking
python manage.py migrate booking
4. 관리자 페이지 등록
만든 모델의 관리를 위해 관리자 페이지에 등록해준다.
# config/admin.py
from django.contrib import admin
from .models import Booking
class BookingAdmin(admin.ModelAdmin):
list_display = ['id', 'subscriber', 'room', 'date_from', 'date_to', 'created', 'updated']
list_editable = ['room', 'date_from', 'date_to']
raw_id_fields = ['subscriber']
admin.site.register(Booking, BookingAdmin)
python manage.py runserver 후에 http://127.0.0.1:8000/admin/booking/ 에 접속하여 예약 몇개를 추가한다.
5. API 환경 만들기
Django REST FrameWork 설치해 사용하기
pip install djangorestframework
# conda install -c conda-forge djangorestframework
config/settings.py에 추가
6. Serializer 클래스 구현하기
Serializer는 요청한 모델을 API로 보여줄 때 사용하는 클래스로, 보통 GET 방식으로 모델에 대한 데이터를 요청했을 때 Serializer를 활용해 데이터를 제공한다.
booking 폴더 아래에 serializers.py 파일을 추가하고, 아래와 같이 작성한다.
from .models import Booking
from rest_framework import serializers
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = Booking
fields = '__all__'
7. 뷰 만들기
booking/views.py에 다음과 같이 입력한다.
from rest_framework import generics
from .models import Booking
from .serializers import BookingSerializer
class BookingList(generics.ListCreateAPIView):
queryset = Booking.objects.all()
serializer_class = BookingSerializer
class BookingDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Booking.objects.all()
serializer_class = BookingSerializer
8. booking/urls.py 생성하고 연결하기
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import *
urlpatterns = [
path('booking/', BookingList.as_view()),
path('booking/<int:pk>/', BookingDetail.as_view()),
]
config/urls.py에도 include 시켜주기
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('booking.urls')),
]
python manage.py runserver
위 명령어를 입력해 API가 잘 동작하는지 확인한다.
http://127.0.0.1:8000/booking/번호 로 접근하면 예약의 상세 정보를 볼 수 있다.
수정도 해보고 제대로 반영이 되었는지 확인한다.
제대로 동작한다.
9. API 문서 만들기
API 문서를 자동으로 생성해주는 앱을 설치한다.
pip install django-rest-swagger
config/setttings.py에 등록한다.
config/urls.py도 수정한다.
from django.contrib import admin
from django.urls import path, include
from rest_framework_swagger.views import get_swagger_view
urlpatterns = [
path('admin/', admin.site.urls),
path('api/doc/', get_swagger_view(title='Booking API Manual')),
path('', include('booking.urls')),
]
get_swagger_view 메서드를 추가하면 각종 API 뷰들을 찾아서 자동으로 문서를 만들어준다.
오류가 났다.
찾아보니 django-rest-swagger 패키지는 더이상 관리를 안한다고 한다. 책이 2019년에 나온걸로 아는데...역시
그래서 삭제하고, drf-yasg를 깔았다. drf-yasg는 django rest framework - yet another swagger generator의 약자다.
pip uninstall django-rest-swagger
pip install drf-yasg
config/settings.py를 수정한다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'booking',
'rest_framework',
'drf_yasg',
]
다음은 config/urls.py를 수정한다. drf-yasg 공식 문서를 참고했다.
https://drf-yasg.readthedocs.io/en/stable/readme.html
# config/urls.py
from django.contrib import admin
from django.urls import path, include, re_path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_url_patterns = [
path('', include('booking.urls')),
]
schema_view = get_schema_view(
openapi.Info(
title="Django API",
default_version='v1',
description="장고 예약 API",
terms_of_service="https://www.google.com/policies/terms/",
),
public=True,
permission_classes=[permissions.AllowAny],
patterns=schema_url_patterns,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('booking.urls')),
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
django.conf.urls.urls()는 장고 3.0에서는 deprecated 되었고, 장고 4.0+에서는 삭제되었다고 한다.
현재 내 장고 버전이 4점대이기 때문에 django.urls.re_path()로 대신하여 사용했다.
실행하고 설정한 url(swagger, reddoc)을 접속하니 잘 나온다.
10. 인증 추가하기
API는 보통 모든 사람이 사용할 수 있게 하지 않고, 문제를 일으킬 수 있으므로 인증 수단을 추가하는 것이 옳다.
다음을 참고하자. https://drf-yasg.readthedocs.io/en/stable/security.html
토큰 인증 방식은 django rest framework에서 제공하는 앱이기 때문에 settings.py에 rest_framework.authtoken 추가만 해주자
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'booking',
'rest_framework',
'rest_framework.authtoken',
'drf_yasg',
]
token 앱도 model을 지원하고 있기 때문에 migrate를 해주자.
python manage.py migrate
booking/views.py도 바꿔보자.
from rest_framework import generics
from .models import Booking
from .serializers import BookingSerializer
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class BookingList(generics.ListCreateAPIView):
queryset = Booking.objects.all()
serializer_class = BookingSerializer
class BookingDetail(generics.RetrieveUpdateDestroyAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
queryset = Booking.objects.all()
serializer_class = BookingSerializer
authentication_classes는 어떤 인증 방식을 사용할 것인지 설정하고,
permission_classes는 인증을 해야만 볼 수 있다는 옵션을 지정할 수 있다.
views.py에서 목록은 인증 기능 처리를 안하고 수정이나 삭제가 가능한 detail에만 인증 기능을 처리했다.
때문에 목록은 인증 없이도 잘 보인다.
하지만 상세보기를 하면 인증이 필요하다는 오류가 나는 것을 볼 수 있다.
token을 발급받아서 접속해보자.
httpie를 설치했다.
brew install httpie
앞서 생성한 obtain_auth_token에서 token을 발급받는다.
http POST http://localhost:8000/api-token-auth/ username="{username}" password="{pw}"
발급 받은 토큰을 카피하고, api에 접근한다. 다음과 같이 입력한다.
http POST http://localhost:8000/booking/ "Authorization: Token {토큰}"
제대로 나오는 것을 볼 수 있다.
11. API 문서에서 Token 기능 사용해보기
다음은 token 획득을 API의 endpoint로 노출시켜보자.
admin에 접속한다.
[Tokens] - [Add]에 사용자를 추가하고 Token을 발급받자.
config/settings.py에 다음을 추가하고, 앱을 실행 후 swagger에 접속한다.
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'DRF Token': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
}
},
"LOGIN_URL": "/admin/login/",
"LOGOUT_URL": "/admin/logout/"
}
SECURITY_DEFINITIONS 옵션을 이용하면 사용자가 Authorize 버튼을 이용해 Token 등의 API 키를 입력할 수 있다.
또 Login_url, logout_url도 추가해서 문서상 로그인/로그아웃 기능도 동작하도록 했다.
오른쪽의 [Authorize]를 클릭하고, 토큰을 입력하자.
추가 후에는 booking API의 테스트를 해볼 수 있다.
curl 명령 등을 이용해 테스트해보면 좋지만 문서 상에서 API 키를 입력할 수 있으면 더 편리하다. 이와 같이 설정하면 API 문서 상에서 API의 동작을 테스트해볼 수 있다.
원하는 테스트 결과를 받을 수 있다.
12. 추가 권한 설정하기
예약에 관한 사항은 관리자는 다 볼 수 있어야 한다. 이런 기능은 권한을 별도로 설정해주면 된다.
앱 폴더에 permissions.py 파일을 만들고 원하는 권한을 입력해주자.
# booking/permissions.py
from rest_framework import permissions
class IsOwnerOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.subscriber == request.user or request.user.is_superuser
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.subscriber == request.user or request.user.is_superuser
IsOwnerOnly는 소유자나 관리자인 경우에만 사용 가능하도록 하는 권한이고,
IsOwnerOrReadOnly는 소유자나 관리자가 아닌 경우 GET 이나 HEAD 같은 조회 기능만 가능하도록 하는 권한이다.
이를 뷰에 적용해보자.
from .permissions import IsOwnerOrReadOnly
class BookingDetail(generics.RetrieveUpdateDestroyAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
queryset = Booking.objects.all()
serializer_class = BookingSerializer
기존에는 토큰이 있는 사용자만 조회할 수 있었다면, 이제 IsOwnerOrReadOnly를 통해 소유자가 아닌 경우 수정은 불가능하도록 만들었다.
'개발 관련 > python' 카테고리의 다른 글
[crawling] HTTP error 403 (0) | 2022.01.12 |
---|---|
[flask] 블루프린트(blueprint) (0) | 2022.01.05 |
[flask] 플러거블 뷰(pluggable view) (0) | 2022.01.05 |
[flask] 리다이렉션과 에러 (0) | 2022.01.05 |
[difflib] 두 문자열 비교하기 (0) | 2021.12.20 |