datetime timezone(feat. None)

HS L·2023년 5월 1일
0

내일배움캠프

목록 보기
41/73
post-custom-banner

문제

장고 심화 프로젝트 진행중 is_complete의 값에 따라 completion_at(DateTimeField)을 null 또는 완료시간으로 업데이트 해주는 기능 구현

시도

is_complete의 bool값에 따라 completion_at을 각각 다음과 같이 구현하려고 했다.
True일 경우 해당시점 시간
False일 경우 값을 null로 변경

True가 됐을 경우는 수정했을때마다 시간이 지정되는 updated_at field가 있어서 값을 동일하게 가져가는 방식으로 구현을 시도했다.

False인 경우
생성시에는 is_complete의 default=False, completion_at=null값으로 생성
후에 is_complete가 True -> False로 변경시 completion_at을 null값으로 수정해주는 식으로 구현해봤다.
null값으로 저장하기 위해서 null, '' 값을 넣어봤는데 타입이 맞지 않아서 계속 오류가 났다.

해결

# 수정
   def put(self, request, todo_id, user_id):
       todo = get_object_or_404(Todo, id=todo_id)

       # 유저 권한을 위한 확인
       if request.user == todo.user:

           # 완료 여부 요청시
           if 'is_complete' in request. data:

               # 미완료 → 완료시 시간 저장
               if request.data['is_complete'] == True and todo.completion_at == None:
                   request.data['completion_at'] = timezone.now()
                   serializer = TodoUpdateSerializer(todo, data=request.data)
                   if serializer.is_valid():
                       serializer.save()
                       return Response(serializer.data, status=status.HTTP_200_OK)
                   else:
                       return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

               # 미완료 상태시 완료시간 제거
               elif request.data['is_complete'] == False:
                   request.data['completion_at'] = None
                   serializer = TodoUpdateSerializer(todo, data=request.data)
                   if serializer.is_valid():
                       serializer.save()
                       return Response(serializer.data, status=status.HTTP_200_OK)
                   else:
                       return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

               # 완료상태에서 is_complete == True요청이 추가로 들어오게 되는경우 처음 완료시점시간이 유지되도록 해준다.
               else:
                   serializer = TodoUpdateSerializer(todo, data=request.data)
                   if serializer.is_valid():
                       serializer.save()
                       return Response(serializer.data, status=status.HTTP_200_OK)
                   else:
                       return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

           # is_complete 요청 없이 내용수정만 진행될 때
           else:
               serializer = TodoUpdateSerializer(todo, data=request.data)
               if serializer.is_valid():
                   serializer.save()
                   return Response(serializer.data, status=status.HTTP_200_OK)
               else:
                   return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

       # 유저 본인이 아니면 접근 불가
       else:
           return Response({"message": "권한이 없습니다!"}, status=status.HTTP_403_FORBIDDEN)

완료상태가 True인 경우 처음에는 timezone을 몰라서 updated_at의 시간과 동일한 값으로 지정을 하는 과정을 한번 더 거쳤었다. 동작하는데 있어서 결과차이는 없었지만 한번 더 저장하는 과정을 줄이기 위해 timezone 또는 datetime을 사용해서 코드 리팩토링을 진행했다.
필요한 import를 진행하고 해당 위치에 값 입력 후 함수실행을 하기 위해 '()'까지 입력해준다. ()를 붙여주지 않으면 실행명령어가 없어서 에러가 난다.

from datetime import datetime
from django.utils import timezone

...
request.data['completion_at'] = timezone.now()
...

다음으로 False일 경우 completion_at의 값을 null로 바꿔줘야 하는데
SQL호출 과정에서는 python명령어를 따르기 때문에 null, '' 등의 다른 값을 입력할 수 없고 None으로 지정해주면 값이 없기때문에 null로 저장할 수 있다.

profile
식이
post-custom-banner

0개의 댓글