노마드 코더 Airbnb 클론 코딩

노마드 코더 에어비앤비 클론 코딩 #12 USERS API

gogi masidda 2022. 11. 23. 17:32

User Profile

# users/serializers.py

class PrivateUserSerializer(ModelSerializer):
    class Meta:
        model=User
        exclude = (
            "password",
            "is_superuser",
            "id",
            "is_staff",
            "is_active",
            "first_name",
            "last_name",
            "groups",
            "user_permissions",
        )
#users/ views.py
#.../api/v1/users/me 내 프로필만 보는 url

class Me(APIView):

    permission_classes = [IsAuthenticated] #자세한 정보는 로그인한 본인에게만 보여야하므로.

    def get(self, request): #유저 정보 보기
        user= request.user
        serializer = serializers.PrivateUserSerializer(user)
        return Response(serializer.data)

    def put(self, request): #유저 정보 수정
        user = request.user
        serializer = serializers.PrivateUserSerializer(user, data=request.data, partial=True,)
        if serializer.is_valid():
            user = serializer.save()
            serializer = serializers.PrivateUserSerializer(user)
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

Create User

#users/ views.py 
#.../api/v1/users

class Users(APIView): #유저 생성

    def post(self, request):
        password = request.data.get('password')
        if not password: #유저가 password를 보내지 않으면.
            raise ParseError
        serializer = serializers.PrivateUserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            user.set_password(password) #그냥 저장하면 raw_password가 됨. 우리는 hash화된 password가 필요함.
            user.save()
            serializer = serializers.PrivateUserSerializer(user)
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

serializer는 위에서 만든 'PrivateUserSerializer'를 사용한다. 

우리가 유저를 만들 때, 따로 설정을 하지 않아도 ModelSerializer가 그 유저의 이름이 이미 존재하는 것인지 확인해준다. 그래서 이것에 대해서는 validation을 하지 않아도 된다.

 

Username

from django.urls import path
from . import views

urlpatterns = [
    path("", views.Users.as_view()),
    path("me", views.Me.as_view()),
    path("@<str:username>", views.PublicUser.as_view()),
]

url을 입력하면,  urls.py에서 path에서 위에서부터 맞는 것을 찾기 때문에, path를 적는 순서도 중요하다.

이를 예방하기 위해, @를 붙이는 방법을 활용한다.

#users/views.py
#.../api/v1/users/username 공개 프로필

class PublicUser(APIView):
    
    def get(self, request, username):
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise NotFound
        serializer = serializers.PublicUserSerializer(user)
        return Response(serializer.data)

 

Change Password

#users/views.py
#.../api/v1/users/change-password

class ChangePassword(APIView):

    permission_classes = [IsAuthenticated]

    def put(self, request):
        user = request.user
        old_password = request.data.get("old_password")
        new_password = request.data.get("new_password")
        if not old_password or not new_password:
            raise ParseError
        if user.check_password(old_password):
            user.set_password(new_password)
            user.save()
            return Response(status=status.HTTP_200_OK)
        else:
            raise ParseError

password를 그냥 저장해두면 안전하지 않다. 그래서 'set_password()'를 사용하여 해시화해서 저장할 수 있다.

old-password가 맞는지 확인하는 데에 django는 좋은 utility를 가지고 있다. 원래 password는 해시화되어 저장되어 있어서, 그냥 맞는지 확인할 수 없다. 그래서 'check_password()'를 사용한다.

 

LogIn, LogOut

#users/views.py
#.../api/v1/users/log-in   .../api/v1/users/log-out

from django.contrib.auth import authenticate, login, logout

class LogIn(APIView):

    def post(self,request):
        username = request.data.get('username')
        password = request.data.get('password')
        if not username or not password:
            raise ParseError
        user = authenticate( #username과 password가 맞지 않으면 user를 리턴하지 않음.
            request, 
            username=username, 
            password=password,
        )
        if user:
            login(request, user)
            return Response({"ok":"Welcome!"})
        else:
            return Response({"error":"Wrong Password"})

class LogOut(APIView):

    permission_classes = [IsAuthenticated]

    def post(self, request):
        logout(request)
        return Response({"ok":"bye!"})

'from django.contrib.auth import authenticate,login,logout' 에서

'authenticate': 만약 username과 password가 맞으면, django는 그에 맞는 user를 리턴한다.

'login': 유저를 로그인시켜주는 function. 로그인시켜줄 user와 request를 보내면 django가 브라우저가 필요한 쿠키와 token등, 중요한 것은 다 자동으로 만들어준다.

Login
Login 성공 / Login 실패 / Logout

728x90