나는 이렇게 학습한다/Debug

[TIL]django__데이터 중복_IntegrityError_ValidationError

daco2020 2021. 11. 21. 17:46
반응형

 오늘 배운 것 

회원가입 시 이메일 정보가 중복되면 에러로 반환하고 싶다. 

장고 view에서 데이터의 중복을 확인하는 방법에는 여러 가지가 있는데 한 번 살펴보자.

 

처음에 나는 회원정보가 있는 Member테이블에서 email 칼럼의 값을 리스트 형태로 가져와 변수에 저장했다.

그리고 요청받은 email 데이터가 해당 리스트에 있는지 확인 하는 식으로 코드를 작성했다. 코드는 다음과 같다.

email_list = Member.objects.values_list("email", flat=True)

if data['email'] in email_list: # data['email']은 요청받은 이메일 정보이다.
	return ~~

 

그리고 동료로부터 배운 두 번째 방법은 exists()매서드를 활용에 중복 여부를 확인하는 방법이다. 

이렇게 하면 굳이 이메일 데이터의 리스트를 만들 필요가 없어진다. 메서드를 활용해 1개 이상 존재하는지 여부를 판단할 수 있기 때문이다.

if Member.objects.filter(email=data["email"]).exists():
	return ~~

 

마지막 세 번째 방법은 models.py에 해당 필드안에 unique=True속성을 부여하는 것이다. 이 속성을 부여하면 1개 이상의 동일한 데이터가 들어올 경우 자동으로 에러 메시지를 반환해 준다. 우리는 이 에러 메시지를 핸들링하여 우리가 원하는 형태로 다시 반환하면 된다.

이를 위해서는 먼저 뷰파일에 IntegrityError를 임포트 한 후, try:~except:을 이용하여 오류를 핸들링할 수 있다. 

from django.db.utils import IntegrityError


try:
 ~~
except IntegrityError:
	return ~~

 

하지만 문제가 발생했다.

내 코드에서 이를 실행하면 정상적으로 작동은 하지만 데이터베이스 테이블에는 pk가 하나씩 증가하는 문제가 생겼다. (사진 첨부)

에러는 잘 잡아내고 리턴도 정상적으로 작동한다.
이메일이 중복되는 에러를 반환한 후에는 pk가 하나씩 밀리는 현상이 발생했다.

아직까지 이 문제는 해결하지 못했다...

테이블에 pk가 늘어나는 것은 장기적으로 볼 때 오류가 생길 위험이 있으므로 해당 코드는 쓰지 않기로 결정했다.

이를 해결하기 위해 또다시 동료의 조언을 듣고 에러 핸들링을 수정하였다. (아래 코드 참고)

 

from django.core.exceptions import ValidationError

class SignupView(View):
    def post(self, request):

        try:
            data     = json.loads(request.body) 
            email    = data["email"]
            password = data["password"]

            if not re.match(email_regexp, email): 
                return JsonResponse({'massage':"EMAIL_ERROR"}, status=400)

            elif not re.match(password_regexp , password):
                return JsonResponse({'massage':"PASSWORD_ERROR"}, status=400)

            else : 
                member = Member(
                    name         = data["name"],
                    email        = email,
                    password     = password,
                    phone_number = data["phone_number"],
                    information  = data["information"]
                )
                member.full_clean() 
                member.save()

                return JsonResponse({'massage':"SUCCESS"}, status=201)

        except ValidationError as e:
            return JsonResponse({'massage':"VALIDATION_ERROR"+" "+str(e)}, status=400)

        except KeyError as e:
            return JsonResponse({'massage':"KEY_ERROR"+" Missing"+str(e)}, status=400)

기존에는 한번에 create 하여 테이블에 데이터를 넣어주었는데, 이번에는 데이터를 member라는 변수에 넣고 full_clean()을 통해 유효성 검사를 수행하도록 수정했다. 참고 링크

full_clean은 위 세 가지를 검증할 수 있다. 내가 사용한 것은 두 번째.

full_clean()을 이용하면 모델에서 지정한 속성에 적합하지 않은 경우, ValidationError를 반환한다. 이를 이용해 에러를 핸들링하니  테이블의 pk가 증가하지 않았고 정상적으로 데이터가 입력되는 것을 확인할 수 있었다.

 


 오늘 느낀 것 

  • 배운 만큼 보인다고 동료가 조언을 해주지 않았다면 무식하게 리스트를 활용하여 중복검사를 진행했을 것이다. 이를 해결하기 위해서는 동료들과 코드를 주기적으로 공유하고, 뿐만 아니라 공식문서나 다른 사람들의 코드를 찾아보면서 시야를 넓혀야겠다는 생각이 들었다.
  • 코딩에 정답이 없음을 느꼈다. 한 가지 답을 찾았다고 거기에 멈추지 말고 다양한 경우와 다양한 코드를 다시 적용해보는 연습을 하면 좋겠다는 생각이 든다. 특히 알고리즘을 풀면서 다양한 시도를 해보는 게 중요하겠다는 생각이 들었다.
  • 위에서 언급한 pk가 증가하는 문제는 아직 원인도 정확히 파악하지 못했다. 다만 추측하기로는 데이터 생성이 먼저 이루어지고 이메일 중복을 거친 후 유효하지 않으면 데이터가 다시 지워지기 때문에 발생한 문제가 아닐까 싶다. 이 부분에 대해서는 멘토님께 문의를 했는데 답을 받는다면 추가로 글에 기재하겠다.
반응형