[TIL] 2022.11.03 Django User, Account(가계부)

xddongx-hyeon2·2022년 11월 13일

1. 진행 상황

  • Account 가계부 모데 생성
  • User 모델 생성
  • 가계부 CRUD API 생성
  • User 회원가입, 로그인, 로그아웃 생성

2. 진행 상황 리뷰

(1) Accounts app

# accounts/models.py
from django.db import models

from users.models import User


class Account(models.Model):
    amount = models.PositiveIntegerField(verbose_name="금액")
    memo = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="작성자")
    is_delete = models.BooleanField(default=False, verbose_name="삭제여부")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="작성시간")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="수정시간")

    def __str__(self):
        return f"{self.amount}: {self.memo[:20]}"
  • 삭제 여부에 따라 복구가 가능하다.
# accounts/view.py
class AccountDetail(APIView):
	...
    
    def delete(self, request, pk):
        """
        가계부 삭제
        DELETE /api/v1/accounts/<pk>/
        """
        user = request.user
        account = self.get_account(pk=pk, author=user)
        delete = {"is_delete": "true"}
        serializer = serializers.AccountsIsDeleteSerializer(account, data=delete)

        if serializer.is_valid():
            serializer.save()
            return Response(status=status.HTTP_204_NO_CONTENT)
        return Response(status=status.HTTP_400_BAD_REQUEST)
  • 가계부 항목 삭제 시 is_delete : true로 변경해 준다.
  • 삭제된 항목들을 볼 수 있는 목록에서 복구하고자 하는 항목을 다시 활성화할 수 있다.

(2) Users app

# users/models.py
from django.contrib.auth.models import AbstractUser, User
from django.db import models


class User(AbstractUser):
    """
    TODO
    email -> password reset 인증에 사용 예정
    """

    username = models.EmailField(max_length=150, unique=True, verbose_name="username")
    first_name = models.CharField(max_length=30, editable=False)
    last_name = models.CharField(max_length=30, editable=False)
    name = models.CharField(max_length=100, verbose_name="name")
    phone = models.CharField(max_length=20, verbose_name="phone")

    def __str__(self):
        return self.username
  • 이번엔 Usernamer을 살렸지만 필드 타입을 email로 변경해 보았다.
  • email은 비밀번호를 변경할 때 본인 확인의 목적으로 살려 두었어.
# users/views.py
class Login(APIView):
    def post(self, request):
        user = authenticate(
            username=request.data.get("username"), password=request.data.get("password")
        )
        if user is not None:
            serializer = serializers.UsersSerializer(user)
            token = TokenObtainPairSerializer.get_token(user)
            refresh_token = str(token)
            access_token = str(token.access_token)
            response = Response(
                {
                    "user": serializer.data,
                    "message": "login success",
                    "token": {
                        "access": access_token,
                        "refresh": refresh_token,
                    },
                },
                status=status.HTTP_200_OK,
            )
            return response
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)


class Logout(APIView):
    def post(self, request):
        """
        로그아웃
        POST /api/v1/users/logout/
        """
        try:
            refresh_token = request.data["refresh"]
            token = RefreshToken(refresh_token)
            token.blacklist()

            return Response(status=status.HTTP_205_RESET_CONTENT)
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST)
  • User마다 Token을 발급하여 유저를 식별하도록 만들어 보았다.

3. Today I Learned

Account(가계부) 삭제/복구

웹 개발을 처음 배울 때 블로그를 만들어보았다. 게시글을 삭제하는 방법도 있지만 비활성화하는 방법도 있다는 것을 듣고 구현해 본 경험이 있다. 그때의 경험이 이번 가계부 삭제/복구 기능을 구현하는데 좋은 발판이 되었다. 역시 경험만큼 좋은 solution은 없는거 같다.

Rest Framework TokenAuthentication

DRF에서 지원하는 인증에는 SessionAuthentication, BasicAuthentication, TokenAuthentication 세 가지가 있다. 이 세 가지 중 Token을 사용해 보았다. 초기 로그인 시에 username/password로 Token을 발급하고, 이 Token을 매 API 요청에 담아서 보내어 인증을 처리한다. 하다보니 JWT Token과 DRF의 Token을 혼동하며 사용했다는 기분이 들었다. 다음엔 JWT Token을 이용하여 명확하게 구현을 해볼 생각이다.

0개의 댓글