장고 심화 프로젝트 진행중 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로 저장할 수 있다.