<이전 코드/>
def SocialSiginin(**kwargs): # 소셜 로그인/회원가입
# 각각 소셜 로그인에서 유저 정보를 받아오고 None인 값들은 빼줌
data = {k: v for k, v in kwargs.items() if v is not None}
email = data.get("email")
signin_type = data.get("signin_type")
if not email:
# email이 없으면 회원가입이 불가능하므로 프론트에 error메시지와 http status를 보냄
return Response(
{"error": "해당 계정에 email정보가 없습니다."}, status=status.HTTP_400_BAD_REQUEST
)
try:
user = User.objects.get(email=email)
if signin_type == user.signin_type:
if user.is_active == 0:
return Response(
{"message": "탈퇴한 계정입니다."}, status=status.HTTP_403_FORBIDDEN
)
# 로그인 타입이 같으면, 토큰 발행해서 프론트로 보내주기
refresh_token = RefreshToken.for_user(user)
access_token = CustomTokenObtainPairSerializer.get_token(user)
return Response(
{
"refresh": str(refresh_token),
"access": str(access_token.access_token),
},
status=status.HTTP_200_OK,
)
else:
# 유저의 다른 소셜계정으로 로그인한 유저라면, 해당 로그인 타입을 보내줌.
# (프론트에서 "{signin_type}으로 로그인한 계정이 있습니다!" alert 띄워주기)
return Response(
{"error": f"{user.signin_type}로 이미 가입된 계정이 있습니다!"},
status=status.HTTP_400_BAD_REQUEST,
)
except User.DoesNotExist:
# 유저가 존재하지 않는다면 회원가입시키기
new_user = User.objects.create(**data)
new_user.set_unusable_password() # pw는 사용불가로 지정
new_user.save()
# 회원가입 후 토큰 발급해서 프론트로 보냄
refresh_token = RefreshToken.for_user(new_user)
access_token = CustomTokenObtainPairSerializer.get_token(new_user)
return Response(
{"refresh": str(refresh_token), "access": str(access_token.access_token)},
status=status.HTTP_200_OK,
)
<문제점/>
- 일단, 이 코드는 이전 프로젝트의 다른 팀원 분이 작성한 코드로 거의 비슷하게 작성했기 때문에 내가 작성한 코드라고 할 수 없다
- 그래서 내가 작성한 코드라고 당당히 말할 수 있도록 코드를 보고 어떤 부분을 고치면 좋을지 고민했다
- 위 코드에서 내 마음에 걸린 건 try-except문이었다(최근 추천 함수 리팩토링에도 try-except문을 썼는데...ㅋㅋㅋ내친 김에 그것도 다시 고쳐봐야겠다)
- try-except문을 사용하면 가장 안 좋은 점이 모르는 사람이 코드를 봤을 때 어떤 에러 때문에 예외 처리를 한 건지 명확히 알 수 없다는 점이다
- 이 코드는 except문에 user가 존재하지 않으면 이렇게 해라 라고 되어 있기 때문에 모르는 사람이 봐도 왜 이렇게 작성된 건지 알 수 있지만..!
- 장고 공식 문서를 보다가 다른 방식도 있다는 걸 알게 되었으니 그걸 적용해 보고 싶은 마음도 있다
Django
The web framework for perfectionists with deadlines.
docs.djangoproject.com
<수정한 코드/>
def SocialSignin(**kwargs): # 소셜 로그인/회원가입
# 소셜 로그인에서 유저 정보를 받아오고 None인 값들은 빼줌
data = {k: v for k, v in kwargs.items() if v is not None}
email = data.get("email")
signin_type = data.get("signin_type")
if not email:
# email이 없으면 회원가입이 불가능하므로 프론트에 error메시지와 http status를 보냄
return Response(
{"error": "해당 계정에 email정보가 없습니다."}, status=status.HTTP_400_BAD_REQUEST
)
user, created = User.objects.get_or_create(email=email, defaults=data)
if created:
user.set_unusable_password()
user.save()
# 회원가입 후 토큰 발급해서 프론트로 보냄
refresh_token = RefreshToken.for_user(user)
access_token = CustomTokenObtainPairSerializer.get_token(user)
return Response(
{
"refresh": str(refresh_token),
"access": str(access_token.access_token),
},
status=status.HTTP_200_OK,
)
else:
# DB에서 찾은 사용자와 로그인 타입이 일치하는 경우
if user.signin_type == signin_type:
if user.is_active == 0:
return Response(
{"message": "탈퇴한 계정입니다."}, status=status.HTTP_403_FORBIDDEN
)
refresh_token = RefreshToken.for_user(user)
access_token = CustomTokenObtainPairSerializer.get_token(user)
return Response(
{
"refresh": str(refresh_token),
"access": str(access_token.access_token),
},
status=status.HTTP_200_OK,
)
else:
return Response(
{"error": f"{user.signin_type}로 이미 가입된 계정이 있습니다!"},
status=status.HTTP_400_BAD_REQUEST,
)
- try-except문 대신 장고 쿼리셋API 중 하나인 get_or_create 메서드를 사용해보았다
- 해당 메서드는 변수를 obj, created 이렇게 2개 설정해서 DB에 찾는 객체가 있다면 obj 변수에 해당 객체가 들어가고 created 변수에는 boolean값으로 false가 들어간다
- 찾는 객체가 없다면 새롭게 객체를 생성해서 obj에 해당 객체가 들어가고, created에는 true가 들어간다
- 이렇게 수정함으로써 코드의 가독성이 높아지고, 실제로 코드가 동작할 때에도 try-except문으로 되어 있으면 try문을 무조건 통과해서 에러가 발생하면 그때 except로 빠지는데 수정한 코드에서는 바로 if문이든 else문이든 코드가 바로 실행되니 불필요한 과정을 줄였다고 볼 수 있다