django의 기본 구조를 익히며 모델링과 간단한 뷰를 작성해보는 django CRUD를 마쳤다.
이번에는 실제 사이트를 구현해보는 프로젝트를 해보게 되었다.
실습해볼 사이트는 인스타그램이고, 해당 사이트를 클론 코딩하는 Westagram Project를 진행하게 되었다.
가상환경 설정 같은 초기 세팅 부분은 CRUD 포스팅에서 다뤄봤으므로 생략하겠다.
회원가입과 로그인 뷰를 작성하려면 먼저 회원 모델링이 필요하다.
회원과 관련된 로직(로그인,회원가입)을 처리할 User 앱을 생성하기 전에, 모델링 기능을 명시한 feature/models git branch를 생성하였다.
git checkout main # 브랜치 생성은 꼭 main 에서 해야 된다.
git branch feature/models # model 기능을 브랜치 이름에 적어 명시해주었다.
다음으로 User 앱을 생성하였다.
# feature/models 에서 실행
python manage.py startapp users # manage.py 가 위치한 디렉토리에서 실행.
다음으로 모델링 작업인 User 테이블을 생성했다.
# users/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(max_length=100, unique=True)
password = models.CharField(max_length=200)
phone_number = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'users'
email
: 이메일(django에서 지원하는 EmailField
사용, 중복된 이메일을 제한하기 위해 unique=True
삽입)password
: 비밀번호(암호화 해싱을 대비하여 길이 제한을 200자로 설정) create_at
, updated_at
: 생성 날짜와 수정 날짜, 생성,수정시 자동으로 설정됨class Meta
: 관계형 데이터베이스에 저장될 테이블 이름 설정작업을 완료하고
모델링 작업이 끝나고 수정 요청을 진행하고 최종적으로 이상이 없어 정상적으로 merge가 완료되었다.
브랜치를 main 브랜치로 바꿔 pull을 해 로컬 스토리지를 최신화하고, feature/sign 브랜치를 생성해서 회원가입 기능 구현을 진행하였다.
import json, re [1]
from django.views import View
from django.http import JsonResponse
from users.models import User
class SignUpView(View):
def post(self,request):
try: [2]
data = json.loads(request.body)
email = data['email'] [3]
password = data['password']
phone_number = data['phone_number']
REGEX_EMAIL = r'^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' [4]
REGEX_PASSWORD = r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$'
REGEX_PHONE_NUMBER = r'^(010)\d{8}$'
if not re.match(REGEX_EMAIL, email): [5]
return JsonResponse({"message" : "INVALID_EMAIL"}, status = 400)
elif not re.match(REGEX_PASSWORD, password):
return JsonResponse({"message" : "INVALID_PASSWORD"}, status = 400)
elif not re.match(REGEX_PHONE_NUMBER, phone_number):
return JsonResponse({"message" : "INVALID_PHONE_NUMBER"}, status = 400)
elif User.objects.filter(email = email).exists():
return JsonResponse({"message" : "DUPLICATED_EMAIL"}, status = 409)
User.objects.create( [6]
name = data["name"],
email = email,
password = password,
phone_number = phone_number
)
return JsonResponse({"message" : "SUCCESS"}, status = 201)
except KeyError as e: [7]
return JsonResponse({"message" : f"KEY_ERROR : ENTER_YOUR_{e.args[0].upper()}"}, status = 400)
[1] : 비밀번호, 이메일, 핸드폰 번호 검증에 필요한 정규식 패키지 re
import
[2] : http request body에 해당되는 key 값이 포함되어 있지 않을 때 KeyError 메세지를 반환하기 위해 try/except
예외처리 사용
[3] : http request에 포함된 body를 json 형태로 load한 내용을 변수화(email, password, phone_number)
[4] : 검증에 맞는 정규식 사용
1) 이메일 : [소문자,대문자,숫자] + @
+ [소문자,대문자,숫자] + .
+ [소문자,대문자,숫자]의 형식
2) 비밀번호 : 최소 1개의 대소문자,1개의 특수문자, 1개의 숫자로 이루어져야 하며, 8자 이상이어야 함
3) 핸드폰 번호 : 010으로 시작, 8개의 숫자
[5] : 회원가입시 조건을 만족하지 못했다면 관련된 에러 메세지 출력
1) 이메일 조건 만족 X
2) 비밀번호 조건 만족 X
3) 핸드폰번호 조건 만족 X
4) 중복된 이메일 - 테이블을 순회하면서 맞는 조건을 검색하고 쿼리를 반환하는 filter 메소드를 사용하므로 else문을 써서 제일 뒤로 빼놓음
[6] : 조건을 만족하였다면 create
메서드를 사용하여 테이블에 http request 저장 후 SUCCESS 메시지, 200코드 반환
[7] : [2]번 KeyError 예외처리, 에러가 발생한 Key값 메세지에 넣어서 반환. key 값은 모델링 수정 시 추가가 될 수 있으므로 확장성을 위해서 해당 에러를 try/except
로 예외처리함
View를 완성하였다면 View를 호출할 URLconf도 정의를 해 주어야 한다.
# westagram/urls.py
from django.urls import path, include
urlpatterns = [
path('users', include('users.urls')),
]
# users/urls.py
from django.urls import path
from users.views import SignUpView
urlpatterns = [
path('/signup', SignUpView.as_view()),
]
URLconfs 설정까지 완료했다면 View가 정상적으로 작동하는지 확인해 보겠다.
정상 작동하는 것을 확인했다. 똑같이 git에 push하는 과정을 거치고 merge까지 완료하였다.
회원 가입 뷰가 있다면 로그인 뷰도 있어야 한다.
class SignInView(View):
def post(self,request):
try: [1]
data = json.loads(request.body)
email = data['email']
password = data['password']
if not User.objects.filter(email = email, password = password).exists(): [2]
return JsonResponse({"message" : "INVALID_USER"}, status = 401)
return JsonResponse({"message" : "LOGIN SUCCESS"}, status = 200)
except KeyError as e:
return JsonResponse({"message" : f"KEY_ERROR : {e.args[0].upper()}"}, status = 400)
[1] : http request의 body 부분에서 json 형식으로 받은 로그인에 필요한 email, password 정보를 딕셔너리 형태로 변환, 변수 지정
[2] : 조건에 해당되는 이메일, 패스워드가 존재하는지 True/False로 반환받기 위해서 exist() 메서드 사용,
# users/urls.py
from django.urls import path
from users.views import SignUpView , SignInView
urlpatterns = [
path('/signup', SignUpView.as_view()),
path('/signin', SignInView.as_view()),
]
정상적으로 로그인에 성공했다.
view에서 SigninView를 import하고 패스 설정도 완료하였다.
git push 과정을 거친 뒤 성공적으로 merge를 완료하였다.