이번에는 저번에 블로깅한 View의 다른버전입니다.
기본적인 흐름은 아래와같습니다.
- 유효성검사를 modules로 구현
- 직접 모듈 내에서 return이 아닌 raise로 예외발생
- except란에 각 예외별로 리턴값을 작성
- 예외를 종류별로 나누기위한 Exceptions.py 생성
폴더 구조는 아래와 같습니다.
모듈 설명
exceptions.py
우선 코드먼저 보여주는게 좋을 것 같습니다.
class EmailDuplicateError(Exception):
pass
class EmailRegexError(Exception):
pass
class PasswordRegexError(Exception):
pass
class PasswordLengthError(Exception):
pass
class PhoneNumberDuplicateError(Exception):
pass
class PhoneNumberRegexError(Exception):
pass
작성한 이유는 다음과 같습니다. 예외를 raise로 발생시키면 문제가 생깁니다.
예외는 발생되지만 모두 Exception으로 생겨서 에러메세지반환을 구분할수가 없습니다.
그래서 따로 파일을 만들어서 각 예외메세지 구분을 위해 예외의 이름을 구분지어서 클래스로 구현했습니다.
regex_modules
import re
from users.views import *
from users.exceptions import *
class RegexTool():
EMAIL_REGEX = '^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
PHONE_NUMBER_REGEX = '\d{3}-\d{3,4}-\d{4}'
PASSWORD_REGEX = '^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$'
@staticmethod
def email_regex(email):
if User.objects.filter(email = email).exists():
raise EmailDuplicateError
elif not re.match(RegexTool.EMAIL_REGEX, email):
raise EmailRegexError
@staticmethod
def password_regex(password):
if not re.match(RegexTool.PASSWORD_REGEX, password):
raise PasswordRegexError
위와 같이 조건에 맞는다면 즉시 해당에러와 맞는 예외를 발생시켰습니다.
예외를 이러한 구조를 가지게 된 이유는 설명했듯이 모듈을 나눠서 클래스로 구현을 해놓았는데
이 모듈에서 return JsonResponse를 해도 return이 되지않습니다. (이유는 잘 모르겠습니다..)
그래서 직접 예외를 발생시켜서 더이상 불필요한 유효성검사를 진행시키지 않으려고 했습니다.
views.py
import ~~~
from ~~~ import ~~~
class SingUpView(View):
def post(self, request):
try:
data = json.loads(request.body)
username = data['username']
first_name = data['first_name']
last_name = data['last_name']
email = data['email']
password = data['password']
phone_number = data['phone_number']
RegexTool.username_regex(username)
RegexTool.email_regex(email)
RegexTool.phone_number_regex(phone_number)
RegexTool.password_regex(password)
User.objects.create(
username = username ,
first_name = first_name ,
last_name = last_name ,
email = email ,
password = password ,
phone_number = phone_number
)
return JsonResponse({'message' : 'SUCCESS'} , status = 201)
except KeyError:
return JsonResponse({'message' : 'KeyError'} , status = 400)
except EmailDuplicateError:
return JsonResponse({'message' : 'EmailDuplicateError'}, status = 400)
except EmailRegexError:
return JsonResponse({'message' : 'EmailRegexError'}, status = 400)
except PasswordRegexError:
return JsonResponse({'message' : 'PasswordRegexError'}, status = 400)
1. 변화점
- 더이상 함수 내부에서 유효성 검사를 진행하지않고 모듈의 클래스로 진행합니다.
- 유효성검사에 필요한 코드, 변수들은 클래스 내부에 존재합니다.
- 코드 중간에 에러값을 return 하지않고 예외처리로 아래쪽에 error리턴값들을 모아놓았습니다.
2.문제점
여기보여드린코드는 사실상 일부분입니다..
예외의 종류가 10종류가 넘었습니다. 예외처리 구문이 view.py의 나머지 구문보다 압도적으로 많아졌습니다.
ver.1과 ver.2의 작성의도? 가장 중요시여긴점
제가 ver.1과 ver.2중에 가장 중요시 여긴점은 바로 불필요한 흐름을 제거하는것이였습니다.
중복검사를 통과하지못한 데이터는 유효성검사로 넘어가지않고 그즉시 Error메세지를 반환하는것을 목표였습니다.
중복검사를 통과하지못하였는데 멈추지않는다면 어차피 들어가지못할 데이터들이 다른검증들을 또 받고있기때문입니다.
그래서 멈추기위해 2가지 방법을 고민했습니다.
- 그자리에서 JsonResponse 반환하기
- 그자리에서 raise로 예외를 발생시켜 예외처리하기
현재버젼이 2번 버젼입니다.각각 장단점이 있었고 몇가지 오류사항이 있었습니다.
1.JsonResponse 에러사항
가장 첫번째는 코드가 안이쁘다는것입니다.
return JsonResponse 라는 리턴문의 가장 기본뼈대만해도 굉장히 긴 문장입니다.
각각 검사시에 조건 충족을 못하면 JsonResponse가 계속 등장합니다.
다완료하면 제일마지막에도 등장하고 KeyError예외처리에도 등장합니다.
두번째는 위의 유효성검사 함수들을 모듈로 넘겨서 작성하면 return JsonResponse가 정상작동하지 않는다는 것 입니다.
예상되는 오류사항은
- 유효성검사모듈에 djang.http 모듈을 임포트하지않아서
- 그냥 안되는것이여서
이 두개정도입니다. 사실 이부분의 오류를 처리하려는도중 2번방법이 떠올라서 2번방법으로 진행했습니다.
2.raise 방식 에러사항
정확히 표현하면 제가한 raise방식의 에러사항입니다.
첫번째는 에러사항들이 많아질수록 커스텀Error클래스를 모아놓은 exceptions.py파일의 크기가 커진다는것입니다.
두번째는 views.py의 실제 실행되는 클래스들에서도 예외처리가 많아져 예외처리코드가 try구문에비해 너무 커졌습니다.
다음 포스팅할 ver3의 방식과 그이유
저는 ver.1, ver.2 작업을하면서 한가지 의문이 들었습니다.
굳이 매번 Response를 리턴써야 해야할까!?
앞에 두가지 어떠 방식으로든 수많은 Response 코드가 나와있는데 이걸 줄일수는 없을까?!
해서 생각한 방법이 result변수에 아래와 같은 코드로 생성시켰습니다.
result = {'message' : None}
JsonResponse와 비교해본다면
return JsonResponse({'message' : 'SUCCESS'} , status = 201)
return JsonResponse( 딕셔너리 , status = 201)
중간에 딕셔너리가 들어가는것을 확일할 수 있습니다.
이렇게 딕셔너리 값을 바꿔버리는 방식으로 다음 버젼을 진행했습니다.
'Python > Django' 카테고리의 다른 글
[Django] ver.3 피드백 모음 (0) | 2022.06.19 |
---|---|
[Django] Westagram 회원가입 기능 작성해보기 ver.3 (0) | 2022.06.13 |
[Django] Westagram 회원가입 기능 작성해보기 ver.1 (0) | 2022.06.12 |
[Django] QuerySet 기본적인 속성과 Field lookups (0) | 2022.06.09 |
[Django]ManyToMany Field 는 왜 사용할까 (0) | 2022.06.08 |