일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 자료구조
- 파이썬
- 자바스크립트
- clone coding
- 인증인가
- 백준
- 파이썬리스트컴프리헨션
- clone-coding
- 알고리즘
- DP
- django
- 파이썬문법
- 윈도우우분투듀얼부팅
- Python
- CSS
- docker
- *args
- decorator
- 인터넷 네트워크
- 코딩테스트파이썬
- promise
- 파이썬입출력
- wecode
- 해시충돌
- QuerySet
- bcrypt
- JavaScript
- **kwargs
- RESTfulAPI
- 리스트컴프리헨션
- Today
- Total
개발기록장
[Django] 인스타그램 클론 코딩(1) - 회원가입 기능 구현 본문
[다음 글]
[Django] 인스타그램 클론 코딩(2) - 로그인 기능 구현
[Django] 인스타그램 클론 코딩(2) - 로그인 기능 구현
인스타그램은 전화번호, 사용자 이름, 이메일 중 하나와 패스워드로 로그인을 할 수 있다. 이를 views.py에 LoginView에 작성하였다. views.py - LoginView 클래스에서 로그인 기능 처리 import jwt import json i..
devvvyang.tistory.com
1. 구현해야 할 기능
- 사용자와 관련된 기능을 처리할 app생성 (User 이름으로 생성함)
- 회원가입 시 이메일, 사용자이름(닉네임), 전화번호는 필수로 입력 받는다
- 이메일에는 반드시 '@'과 '.'이 들어가있어야 하며 이를 만족하지 않을 시 에러를 반환한다. (정규표현식 사용하기)
- 패스워드는 반드시 8자리 이상이여야하며 이를 만족하지 않을 시 에러를 반환한다.
2. user/models.py
from django.db import models
class User(models.Model):
email = models.EmailField(max_length=50, unique=True)
name = models.CharField(max_length=20, unique=True)
phone = models.CharField(max_length=15, unique=True)
password = models.CharField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'users'
-
회원 정보를 관리하는 테이블을 User라는 이름의 클래스를 통해 만들었다.
-
email(이메일), name(닉네임), phone(전화번호)는 중복될 수 없으므로 unique=True 옵션을 사용했다.
-
password는 암호화된 문자열로 저장되어야 하기 때문에 max_length를 300으로 잡아주었다.
-
데이터의 생성 시점을 관리하는 필드인 created_at에는 auto_now_add 옵션을 주어서 데이터가 들어오면 자동으로 그 시점을 저장할 수 있게 하였다.
-
데이트의 수정 시점을 관리하는 필드인 updated_at에는 auto_now 옵션을 주어 데이터가 수정되면 자동으로 그 시점을 저장할 수 있게 하였다.
3. user/views.py (전체 로직 설명)
import re
import json
import bcrypt
from django.views import View
from django.http import JsonResponse
from django.db.models import Q
from .models import User
MINIMUM_PASSWORD_LENGTH = 8
def validate_email(email):
pattern = re.compile('^.+@+.+\.+.+$')
if not pattern.match(email):
return False
return True
def validate_password(password):
if len(password) < MINIMUM_PASSWORD_LENGTH:
return False
return True
def validate_phone(phone):
pattern = re.compile('^[0]\d{2}\d{3,4}\d{4}$')
if not pattern.match(phone):
return False
return True
class SignupView(View):
def post(self, request):
data = json.loads(request.body)
email = data.get('email', None)
name = data.get('name', None)
phone = data.get('phone', None)
password = data.get('password', None)
# KEY_ERROR check
if not(password and email and name and phone):
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
# validation check
if not validate_email(email):
return JsonResponse({'message': 'EMAIL_VALIDATION_ERROR'}, status=422)
if not validate_password(password):
return JsonResponse({'message': 'PASSWORD_VALIDATION_ERROR'}, status=422)
if not validate_phone(phone):
return JsonResponse({'message': 'PHONE_VALIDATION_ERROR'}, status=422)
# unique check
if User.objects.filter(Q(email=email) | Q(name=name) | Q(phone=phone)).exists():
return JsonResponse({'message': 'USER_ALREADY_EXISTS'}, status=409)
User.objects.create(
email = email,
name = name,
phone = phone,
password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
)
return JsonResponse({'message': 'SUCCESS'}, status=200)
-
SignupView에서 http post 메소드로 요청이 들어올 시 회원가입 처리
-
http resquest에서 이메일(email), 사용자 이름(name), 전화번호(phone), 비밀번호(password)를 입력받아서 회원가입이 되도록 구현
-
이메일, 전화번호, 비밀번호는 내가 정의한 validate 함수를 통해 특정 포맷을 따르지 않을 시 에러를 반환한다.
-
이미 가입되어 있는 이메일 또는 사용자 이름 또는 전화번호로는 가입이 안되도록 구현하였다.
-
bcrypt.hashpw()메소드를 이용하여 사용자가 입력한 비밀번호를 평문이 아닌 암호화된 문자로 DB에 저장하도록 구현하였다.
** 암호화에 대한 설명은 이곳을 참고!!
4. 발생할 수 있는 에러와 처리 방법
1) Key Error
class SignupView(View):
def post(self, request):
data = json.loads(request.body)
email = data.get('email', None) # request body에 'email'이라는 키 값이 없으면 None으로 처리
name = data.get('name', None) # request body에 'name'이라는 키 값이 없으면 None으로 처리
phone = data.get('phone', None) # request body에 'phone'이라는 키 값이 없으면 None으로 처리
password = data.get('password', None) # request body에 'password'이라는 키 값이 없으면 None으로 처리
# KEY_ERROR check
if not(password and email and name and phone):
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
(생략..)
-
http request body에서 email, name, phone, password라는 key 값이 들어오지 않은 값 default로 None값을 세팅하도록 구현하였다.
-
회원가입 시 email, name, phone, password는 필수로 입력받아야 하는 값이기 때문에 넷 중 하나라도 None이라면 key error를 return하여 key error를 처리하였다.
2) 유효성 검사
import re
(생략..)
MINIMUM_PASSWORD_LENGTH = 8
def validate_email(email):
pattern = re.compile('^.+@+.+\.+.+$')
if not pattern.match(email):
return False
return True
def validate_password(password):
if len(password) < MINIMUM_PASSWORD_LENGTH:
return False
return True
def validate_phone(phone):
pattern = re.compile('^[0]\d{2}\d{3,4}\d{4}$')
if not pattern.match(phone):
return False
return True
class SignupView(View):
def post(self, request):
(생략..)
# validation check
if not validate_email(email):
return JsonResponse({'message': 'EMAIL_VALIDATION_ERROR'}, status=422)
if not validate_password(password):
return JsonResponse({'message': 'PASSWORD_VALIDATION_ERROR'}, status=422)
if not validate_phone(phone):
return JsonResponse({'message': 'PHONE_VALIDATION_ERROR'}, status=422)
(생략..)
-
이메일, 패스워드, 전화번호는 특정 포맷을 따라야하므로 유효성 체크를 해야한다.
-
django에서 제공하는 validation 함수도 있지만, 여기서는 내가 직접 validation 함수를 작성하여 사용하였다.
-
만일 이 views.py 외의 다른 곳에서 이러한 함수가 쓰일 경우에는 반드시 이러한 함수만 모아서 별도의 파일로 저장하여 import로 불러와서 쓸 수 있게 해야한다. 하지만 지금 상황처럼 이곳에서만 쓰인다면 별도의 파일로 만드는 것은 선택사항이다. (나는 별도의 파일로 저장하는게 더 깔끔하고 좋은 것 같다.)
-
email은 '@'앞에는 아무 문자가 제한 없이 들어올 수 있으며, '@'과 '.' 사이, 그리고 '.' 뒤에도 아무 문자열이 제한 없이 들어올 수 있게 하는 패턴을 파이썬 정규표현식을 이용하여 구현하였다.
-
password는 8자리 이상인지만 체크한다. 이때 8이라는 상수는 변수로 지정해서 쓰는 것이 바람직하다.
-
전화번호의 경우는 '-'없이 숫자만 입력하도록 하였으며, 이것도 파이썬 정규표현식을 이용하여 구현하였다.
-
각 표현식에 맞는지를 체크하여 포맷에 맞지 않은 경우, SignupView에서 각 상황에 맞는 에러 메세지와 에러 코드를 반환하도록 처리하였다.
3) 중복 데이터 검사
class SignupView(View):
def post(self, request):
(생략..)
# unique check
if User.objects.filter(Q(email=email) | Q(name=name) | Q(phone=phone)).exists():
return JsonResponse({'message': 'USER_ALREADY_EXISTS'}, status=409)
(생략..)
-
회원가입 시 이미 등록되어 있는 이메일, 사용자 이름, 전화번호로는 가입할 수 없으므로 이미 등록된 이메일 또는 사용자 이름 또는 전화번호를 입력했을 시 이미 등록된 사용자라는 에러를 반환하도록 구현하였다.
-
여기서 에러처리를 함으로서 DB에서도 중복 데이터 에러가 나지 않도록 할 수 있다.
'TIL > Django' 카테고리의 다른 글
[Django] 인스타그램 클론 코딩(3) - Authorization Decorator 만들고 활용하기 (1) | 2021.02.08 |
---|---|
[Django] 인스타그램 클론 코딩(2) - 로그인 기능 구현 (0) | 2021.02.02 |
[Django] ManyToManyField 설정과 데이터 조회 방법 (0) | 2021.01.27 |
[Django] QuerySet 메소드 정리 (2) - CRUD (5) | 2021.01.25 |
[Django] QuerySet 메소드 정리 (1) - 연결된 테이블에서 데이터 조회(정참조/역참조) (1) | 2021.01.21 |