AI 웹개발반

[TIL] 개인과제 중 마주친 크고 작은 오류들 기록.

째깍단 2023. 4. 28. 20:59

기록해두면 다시 만났을때 안 틀릴거라는 마음으로 개인과제 회고 및 기록해본다.. 제발!

 

과제는 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이 있음을 깨닫고.. 

고마워 ERD..

 

 

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 강의 다시 듣고 공부 쭉 해야 따라갈 수 있을 듯..

 

일단 과제 끝낸 나는 칭찬....굿... 굿보이....