[TIL] 개인과제 중 마주친 크고 작은 오류들 기록.
기록해두면 다시 만났을때 안 틀릴거라는 마음으로 개인과제 회고 및 기록해본다.. 제발!
과제는 DRF homework, todolist 만들기!
- 1 - password 암호화
이거 안하면 db에서 유효한 값이 없다고 아예 데이터 안 가져옴!
순조롭게 signin 시켰으나 password 가 암호화 되지 않는 이슈! 로 인해 "적절한 자료가 없다" 는 오류가 함께 뜬다.
serializers.py 에 set_password로 password를 암호화하는 기능을 추가
def create(self, validated_data):
user = super().create(validated_data)
password = user.password
user.set_password(password) #set_password로 암호화
user.save()
return user
- 2 - 500 403 400 오류가 반복되는 회원 수정기능에서의 고통...
UserView에 함께 코드를 짜고 있던 회원 수정기능이 작동하지 않았다.
put기능에 csrf_exempt 데코레이터를 사용했다.
500 error는 사라지고 여러가지 4xx에러가 나기 시작함.
리프레시 겸 어차피 추가 기능 구현을 위해 공부해야했으므로 분리하여 profile 부분을 만들어보기로 했다!
serializer와 view에서 Profile로 분리해 get, put, delete 내용을 작성했다.
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ['id', 'email', 'username', 'password', 'gender', 'age', 'bio']
read_only_fields = ('id','email') #수정 불가능하도록 read-only로 설정
extra_kwargs = {
'password' : {'write_only' : True}
}
def update(self, instance, validated_data):
user = super().update(instance, validated_data)
password = user.password
user.set_password(password)
user.save()
return user
read_only_fields로 수정기능에서의 예외 설정을 해보았다.
extra_kwargs 로 password를 응답할때 가져오지 않도록 설정했다.
class UserProfileView(APIView):
permission_classes = [permissions.IsAuthenticated,] #login했는지, request 유저인지 먼저 확인
def get(self, request, user_id):
serializer = UserSerializer.get_object_or_404(id=user_id)
return Response(serializer.data, status=status.HTTP_200_OK)
- 오류 해결 과정 1 - get profile
1차로 get 부터 실행되지 않았다. 403.
= user_id를 받아오지 못하며 오류가 생김.
path('profile/', views.UserProfileView.as_view(), name='profile_view'), #여기가 문제였음
urls.py에서 url에 id 값을 넣어주어야 받아올 수 있었다!!!
urlpatterns:[
path('profile/<int:user_id>/', views.UserProfileView.as_view(), name='profile_view'),
...
- 오류 해결 과정 2 - get profile
실행했을 때 serializer 부분에서 데이터에 있는 유저 내용을 가져오지 못하는 문제가 있었다.
데이터에 들어있는 user를 get_object_or_404로 먼져 가져온 후에
serializer에서 user 데이터를 넣어주도록 설정하여 오류를 해결했다.
user = get_object_or_404(CustomUser, id=user_id)
# print(user)
# print(request.user)
serializer = UserProfileSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK)
- 오류 해결 과정 3 - put profile
초기 put 형태
@csrf_exempt
def put(self, request):
serializer = UserSerializer(data=request.data)
user = request.data.get("email",None) ## 수정
print(request.user)
print(user)
if user == request.user:
if serializer.is_valid():
serializer.save()
return Response({'message':'회원 정보 수정 완료'}, status=status.HTTP_201_CREATED)
user data를 request user와 비교해 가져오는 방식을 취하려 했다.
그런데 요청에 의해 가져온 user 데이터와 request user의 데이터는 결국 같은 것인데
if 문에서 비교하는 것이 의미가 없다는 생각도 들고, 이 기능이 계속 작동하지 않아서 다른 방법으로 수정하고자 했다.
=> 생각한 다른 방법 = profile로 분리 후 user_id 받아와서 비교하기
시도2.
이전 코드에서는 첫줄에서 모든 데이터가 가져와지는 문제가 있어 id를 비교하여 일치하는 것만 get하는 방식으로 변경한 것.
def put(self, request, user_id):
user = get_object_or_404(CustomUser, id=user_id) #user 데이터 가져와주기
if user.id == request.user.id: #요청유저와 유저데이터 id 일치 여부 검사
serializer = UserProfileSerializer(user, data=request.data)
serializer.save(user=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
여기에서의 문제점 : 팀원분의 어시스트. 압도적 감사ㅠㅠ
user.id 까지는 작동하지만, request.user.id 는 작동하지 않는다!!
시도3.
current_user = request.user
if user.id == current_user.id: #요청유저와 유저데이터 id 일치 여부 검사
serializer = UserProfileSerializer(user, data=request.data)
그래서 current_user 변수에 request.user를 담아주어 current_user.id를 불러와주도록 변경하여야 한다.
- 약간의 기능 추가? 1 - delete user
def delete(self, request):
serializer = UserSerializer(data=request.data)
serializer.delete()
return Response({'message':'회원 탈퇴 완료'}, status=status.HTTP_201_CREATED)
처음에는 request 한 유저와 유저 데이터를 비교해 바로 지우는 방식으로 하였지만
user가 동일하지않아 실패했을 때의 메시지를 띄워주고 싶었다.
그래서 user_id를 비교해 데이터를 가져오고 if문으로 비교해 같으면 지우도록 하고
else면 권한 없음이 뜨도록 바꾸어주었다.
def delete(self, request, user_id):
user = get_object_or_404(CustomUser, id=user_id) #user 데이터 가져와주기
if user == request.user:
user.delete()
return Response({'message':'회원 탈퇴 완료'}, status=status.HTTP_202_ACCEPTED)
else:
return Response({'message':"권한이 없습니다"}, status=status.HTTP_403_FORBIDDEN)
- 약간의 기능 추가? 2 - completion_record for todo
기본 구현 사항에 is_completed와 completion_at이 있음을 깨닫고..
is_completed 가 True값이되면 completion_at이 기록되는 기능을 만들었다. ** 테스트 미완
def post(self, request, todolist_id):
todo = get_object_or_404(ToDoList, id=todolist_id)
if todo.is_completed == True:
todo.update(completion_at = todo.completion_at)
...
- 기억할 것 -
이번 과제를 진행하면서 계속 한 가지 실수를 자주 했다.
Serializer를 받아올때 인자를 넣는 것을 깜빡한다.
그래서 data = request.data 혹은 id = todo_id 와 같이 비교하는 부분만 넣고
가장 중요한 첫번째 인자!!! 모델!!!!!을 안넣어 오류를 직접 만드는 상태를 여러번 경험했다.
예시를 기록하니 꼭!!!!!! 기억하자!!!!!!
serializer = UserProfileSerializer(user, data=request.data)
#todolist = ToDoList.objects.filter(user=request.user).order_by('-created_date')
serializer = ToDoListSerializer(todolist, many=True)
serializer = ToDoListCreateSerializer(todo, data=request.data)
todo = get_object_or_404(ToDoList, id=todolist_id)
느낀점:
과제.. 쉽지 않았다.
주말동안 serializer 강의 다시 듣고 공부 쭉 해야 따라갈 수 있을 듯..
일단 과제 끝낸 나는 칭찬....굿... 굿보이....