Django - 회원가입/로그인 앱(app) 생성 _ 개선(ver 1.1)

jomminii_before·2020년 2월 8일
2

본 글은 이전에 만들었던 Django - 회원가입/로그인 앱(app) 생성에 대한 1차 개선 버전입니다. (뷰와 경로부분 개선)

뷰 개선

코드 최 상단 부분 입니다.

# 개선 전 버전
import json
from django.views import View
from django.http import JsonResponse
from .models import Account

파일의 최상단에 사용하고자 하는 모듈을 임포트할 때에도 나름의 규칙이 필요합니다. 파이썬에서 강제하는 규칙은 아니고, 우리가 다니는 회사나 속해있는 조직에서 사용하는 컨벤션(convention)에 맞춰야하는 수준입니다. 현재 제가 있는 위코드의 컨벤션에 맞춰 코드를 수정했습니다. 위코드에서는 바로 모듈을 임포트 하는 경우에는 최상단, 두 번째 자리에는 직접 만든 모듈, 마지막에는 장고에서 가져온 모듈을 둡니다. 그리고 각각의 그룹 사이에는 한 칸의 공백을 둡니다.

이러한 컨벤션을 맞추는 과정이 불필요하다고 볼 수도 있겠지만, 여러 사람들이 모여 같이 코드 작업을 하는 경우 이렇게 규칙을 갖는 것이 서로 코드를 공유하고 작업하는 효율성을 높여줍니다.

# 개선 버전
import json

from .models import Account

from django.views import View
from django.http import JsonResponse

첫 번째 뷰인 회원가입 뷰 입니다.

# 개선 전 버전
class SignUpView(View):
    def post(self, request):
        data = json.loads(request.body)
        Account(
            email    = data['email'],
            password = data['password']
        ).save()

        return JsonResponse({'message':'회원가입 완료'},status=200)

회원가입 뷰에서는 먼저 회원가입을 할 때 이미 가입한 이메일인지 확인할 수 있는 코드를 넣었습니다. filterexists메서드를 사용해서 사용자가 입력한 이메일이 기존 DB에 있는지 확인하고, 있으면 status=400(Bad Request)을 리턴하도록 했습니다.

또, 마지막 줄을 개선했습니다. 작성할 당시에는 여기서 보내주는 메시지가 사용자에게 보여질거라는 생각으로 메시지를 작성했는데, 아니었습니다. 해당 메시지는 프론트엔드 개발자가 보는 메시지기 때문에, 사전에 프론트 개발자와 약속된 메시지를 보여줘야합니다. 지금은 그러한 약속이 없기 때문에 statusHttpResponse로 응답하도록 개선했습니다.

마지막으로 예외처리 구문을 추가했습니다. 기존에는 KeyError 처리 구문이 없어서 사용자가 email이나 password값 둘 중 하나 이상을 넣지 않으면 KeyError 500 에러가 떴습니다.

# 에러 예시
KeyError: 'email'
[08/Feb/2020 13:52:13] "POST /account/sign-up HTTP/1.1" 500 71374
# 개선 버전
class SignUpView(View):
    def post(self, request):
        data = json.loads(request.body)
        try :
            if Account.objects.filter(email = data['email']).exists(): # 존재하는 이메일인지 확인
                return HttpResponse(status=400)
            
            Account(
                email    = data['email'],
                password = data['password']
            ).save()
        
            return HttpResponse(status=200) 
        except KeyError:
          return JsonResponse({"message":"INVALID_KEYS"}, status = 400)

다음은 로그인 뷰 입니다.

# 개선 전 버전
class SignInView(View):
    def post(self, request):
        data = json.loads(request.body)

        if Account.objects.filter(email = data['email']).exists() :
            user = Account.objects.get(email = data['email'])
            if user.password == data['password'] :
                return JsonResponse({'message':f'{user.email}님 로그인 성공!'}, status=200)
            else :
                return JsonResponse({'message':'비밀번호가 틀렸어요'}, status = 200)

        return JsonResponse({'message':'등록되지 않은 이메일 입니다.'}, status = 200)

일단은 여기서도 회원가입과 같이 응답으로 넘기는 메시지들을 지웠습니다. 그리고 status 코드를 수정했습니다. 당시에는 제가 짠 로직을 정상적으로 통과했기 때문에 status = 200을 반환해야된다고 생각했습니다. 그렇지 않고 다른 에러 코드를 반환하면 사용자에게 그게 그대로 노출된다고 생각했거든요. 백엔드의 역할에 대해 잘못 이해하고 있었어서 실제와 다르게 사고가 흘러간 것 같습니다.

해당 status 코드는 에러상황을 프론트엔드 개발자에게 전달하기 위한 코드이고, 프론트엔드 개발자는 그 코드를 보고 사용자에게 보여줄 페이지를 개발합니다. 그렇기에 각 논리의 상황에 맞는 status 코드를 리턴해줘야 합니다.

이메일 정보는 맞고 비밀번호는 틀린 경우, 해당 계정 정보를 인증 받지 못했으므로 권한이 없다는 status=401을 리턴해주면 됩니다. 이메일부터 틀린 경우에는 정확한 요청을 받지 못했으므로 status=400을 리턴해주면 됩니다. 사실 기준이 좀 모호한 면이 있기 때문에 실무에서 사용할 때 담당자들 간에 약속을 정해 사용하면 됩니다.

400(잘못된 요청): 서버가 요청의 구문을 인식하지 못했다.
401(권한 없음): 이 요청은 인증이 필요하다. 서버는 로그인이 필요한 페이지에 대해 이 요청을 제공할 수 있다. 상태 코드 이름이 권한 없음(Unauthorized)으로 되어 있지만 실제 뜻은 인증 안됨(Unauthenticated)에 더 가깝다.
-위키백과-HTTP 상태코드

다음 개선할 부분은 비밀번호가 틀렸을 경우를 나타낸 else문 입니다. 해당 else문은 굳이 쓰지 않아도 되었습니다. else를 없애고, 리턴 줄을 앞으로 당기면 똑같은 결과를 가져옵니다. 지울 수 있는 코드는 되도록 없애는게 좋습니다.

그리고 이것도 코드 컨벤션과 관련된 개선사항인데, 각 코드 줄의 줄띄움은 댜른 로직으로 구분될 때 띄우면 좋습니다.

마지막으로 회원가입과 마찬가지로 KeyError 처리 구문을 추가했습니다. 로그인에서도 email을 입력하지 않으면 KeyError 500 에러가 떴거든요!

# 개선 버전
class SignInView(View):
    def post(self, request):
        data = json.loads(request.body)

        try: 
 	       if Account.objects.filter(email = data['email']).exists() :
    	        user = Account.objects.get(email = data['email'])
        	  	# 사이 줄 띄움
            	if user.password == data['password'] :
                	return HttpResponse(status=200)
            
          	    return HttpResponse(status = 401)

       		return HttpResponse(status=400)
 	
        except KeyError:
          return JsonResponse({"message":"INVALID_KEYS"}, status = 400)

경로(URL PATH) 개선

개선 전 버전에서는 url경로를 어떻게 짜야할지 잘 모르겠어서 굳이 sign과 뒤에 붙는 upin을 나누어 경로를 구성했는데요, 다시 보면 기괴한 모습입니다.

# 개선 전 버전
# westa_posting/urls.py
from django.urls import path, include

urlpatterns = [
    path('sign', include('account.urls')),
]

# account/urls.py
from django.urls import path
from .views import SignUpView, SignInView

urlpatterns = [
    path('/up', SignUpView.as_view()),
    path('/in', SignInView.as_view()),
] 

특별한 경로 이름이 필요하지 않다면, 일반적으로 연결된 앱 이름을 첫 경로로 설정한다고 해서 sign을 앱 이름인 account으로 변경했습니다. 그리고 account/urls.py에서 설정된 경로도 sign-upsign-in으로 개선했습니다.

훨씬 보기 낫네요.

# 개선 버전
# westa_posting/urls.py
from django.urls import path, include

urlpatterns = [
    path('account', include('account.urls')),
]


# account/urls.py
from django.urls import path
from .views import SignUpView, SignInView

urlpatterns = [
    path('/sign-up', SignUpView.as_view()),
    path('/sign-in', SignInView.as_view()),
] 

이렇게 첫 번째 버전을 개선해봤습니다. 추가로 배우게 되는 내용으로 기능을 개선하게 되면 추가 포스팅 할 예정입니다.

profile
https://velog.io/@jomminii 로 이동했습니다.

1개의 댓글

comment-user-thumbnail
2022년 7월 15일

안녕하세요. 이전버전 개선된 버전 둘 다 실행해봤습니다.
코드를 잘 입력했고 직접 크롬에 주소 입력해서 실행해봤는데요.
sign-up,sign-in 둘 다 페이지가 작동하지 않는다고 뜹니다.
혹시 이건 웹으로 직접 사용하는 건 제한되는 건가요??

답글 달기