일단 권한을 설정 해야 하니까, Django로 돌아옵시다.
django-rest-knox 라는 패키지를 다운로드 해야합니다.
$ (venv) pip install django-rest-knox
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'notes',
'rest_framework',
'knox',
]
...
# 제일 하단에 추가해줍니다.
# 처음에 10개만 받아오기 위해 PAGE_SIZE를 설정했습니다.
# 그리고 기본 권한을 knox의 token을 기반으로 설정했습니다.
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',),
}
$ (venv) python manage.py makemigrations
$ (venv) python manage.py migrate
이제 기본 권한을 설정했으니, notes 모델에서 owner 필드를 추가해주겠습니다.
notes/models.py
from django.db import models
from django.contrib.auth.models import User
class Notes(models.Model):
text = models.CharField(max_length=255)
owner = models.ForeignKey(
User, related_name="notes", on_delete=models.CASCADE, null=True
)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.text
User 모델을 가져온뒤, foreign key로 설정했네요.
그리고 모델을 수정했으니 다시한번 migrate 해줍니다.
$ (venv) python manage.py makemigrations
$ (venv) python manage.py migrate
views.py에서는 모든 노트를 불러왔던것을 이제 owner별로 불러오는 작업을 해주겠습니다. 그리고, 노트를 만들때, owner 필드에 값을 넣어야겠죠?
notes/views.py
from rest_framework import viewsets, permissions
from .models import Notes
class NoteViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, ]
serializer_class = NoteSerializer
def get_queryset(self):
return self.request.user.notes.all().order_by("-created_at")
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
자 이제, 회원가입 및 로그인에 대한 API 구현을 해보겠습니다.
notes/serializers.py
from rest_framework import serializers
from .models import Notes
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
...
# 회원가입 시리얼라이저
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id", "username", "password")
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user = User.objects.create_user(
validated_data["username"], None, validated_data["password"]
)
return user
# 접속 유지중인지 확인할 시리얼라이저
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id", "username")
# 로그인 시리얼라이저
class LoginUserSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Unable to log in with provided credentials.")
위와같이 serializer를 만들고,
notes/views.py
from rest_framework import viewsets, permissions, generics
from rest_framework.response import Response
from .models import Notes
from .serializers import (
NoteSerializer,
CreateUserSerializer,
UserSerializer,
LoginUserSerializer,
)
from knox.models import AuthToken
....
class RegistrationAPI(generics.GenericAPIView):
serializer_class = CreateUserSerializer
def post(self, request, *args, **kwargs):
if len(request.data["username"]) < 6 or len(request.data["password"]) < 4:
body = {"message": "short field"}
return Response(body, status=status.HTTP_400_BAD_REQUEST)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
return Response(
{
"user": UserSerializer(
user, context=self.get_serializer_context()
).data,
"token": AuthToken.objects.create(user),
}
)
class LoginAPI(generics.GenericAPIView):
serializer_class = LoginUserSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
return Response(
{
"user": UserSerializer(
user, context=self.get_serializer_context()
).data,
"token": AuthToken.objects.create(user),
}
)
class UserAPI(generics.RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
serializer들도 만들어 줍니다.
notes/urls.py
from django.conf.urls import url
from .views import NoteViewSet, RegistrationAPI, LoginAPI, UserAPI
note_list = NoteViewSet.as_view({"get": "list", "post": "create"})
note_detail = NoteViewSet.as_view(
{"get": "retrieve", "patch": "partial_update", "delete": "destroy"}
)
urlpatterns = [
url("^notes/$", note_list, name="note-list"),
url("^notes/(?P<pk>[0-9]+)/$", note_detail, name="note-detail"),
url("^auth/register/$", RegistrationAPI.as_view()),
url("^auth/login/$", LoginAPI.as_view()),
url("^auth/user/$", UserAPI.as_view()),
]
이렇게 url 라우팅도 해주면 장고작업은 끝이납니다.
postman 에서 body에 raw -> JSON형태로
{
"username": "testing",
"password": "1234"
}
를 넣어주시고, http://localhost:8000/api/auth/register/ 와 http://localhost:8000/api/auth/login/ 을 POST 방식으로 실행하면 잘 실행이 될것입니다.
또한 접속된 유저 정보를 보기 위해서는, http://localhost:8000/api/auth/user/ 로 Headers 에 Authorization 항목을 넣고 token 토큰값 으로 GET 실행 하면 유저 정보가 뜨게됩니다.
마지막으로 로그아웃을 구현하는것은 간단합니다.
d_note/urls.py
from django.contrib import admin
from django.urls import path
from notes import urls
from django.conf.urls import include, url
urlpatterns = [
path("admin/", admin.site.urls),
url(r"^api/", include(urls)),
url(r"^api/auth", include("knox.urls")),
]
다음과 같이 설정하면, /api/auth/logout/ 으로 Authorization: token 토큰값 으로 실행하면 로그아웃이 됩니다.
본문 내용을 따라하다가 오류 나는 부분 적어 놓습니다.
...
from django.urls import path
...
from django.conf.urls import include, url <--더이상 사용 안하는 구문
이부분은
from django.urls import path, include
이렇게 한줄로 바꾸고, 아래의 url은 더이상 안쓰는게 맞습니다. 정규식을 쓰려면 re_path 를 추가 하시고 쓰시면 됩니다.
urlpatterns = [
path("admin/", admin.site.urls),
url(r"^api/", include(urls)),
url(r"^api/auth", include("knox.urls")),
]
이부분은
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(urls)),
path("api/auth", include("knox.urls")),
]
이렇게 수정하시면 됩니다.