TIL 20 Django 회원가입&로그인 (1)

CastleQ·2021년 6월 5일
0

django

목록 보기
4/5
post-thumbnail

필자는 백엔드 개발자 지망생으로 장고를 이용한 회원가입 로그인 기능을 간단히 구현해 보았습니다.

지금 작성하는 포스팅은 django의 프로젝트를 생성하였고 초기 셋팅은 완료를 했다는 가정하에 진행 하도록 하겠습니다 !
이전 포스팅은 TIL 11 django프로젝트 생성을 보시면 앱의 생성과 설정 방법을 적어 놨으니 필요하신 분들은 참고 하시기 바랍니다!!

자, 코딩의 세계가 넓다고 하니 제가 한번 가보겠습니다.

Westagram clone coding

위코드에서 진행하는 프로젝트 중 하나로 인스타그램 어플을 장고를 사용하여 기본적인 회원가입과 로그인 기능에 대해서 공부를하고 user앱을 생성해보는 프로젝트이다.
이프로젝트를 진행하면서 느꼈던 점은 새로 접해보는 Django친구랑 익숙해지고 그리고 프레임워크를 사용 하였을 때의 얻는 이점을 직접 코드를 작성하면서 느끼고 개발자로서 새로운 프레임워크를 접했을때 이러한 도구들을 빨리 공부해서 개발하는 방법에 대해 생각해보는 프로세스를 가졌던 것 같다.

물론 공식문서를 찾아보는 방법과 (개발자는 구글링이지❤️) 구글링하는 방법도 많이 는 것 같다.

models.py 작성

from django.db import models

class User(models.Model):
    email        = models.EmailField(unique=True, max_length=50)
    password     = models.CharField(max_length=45)
    phone_number = models.CharField(max_length=45)
    nickname     = models.CharField(max_length=45)

    class Meta:
        db_table = 'users' 

User클래스를 선언하며 models.Model을 상속받아 왔는데 import된 장고의 내장 기능이다. 모델스파이에서는 특별한 커스텀을 하지 않는한 class에 models.Model를 상속받아서 구성을 한다.

📌 tip
python에서 class를 선언할 때에는 첫 글자를 대문자로 해주는 대표적인 컨벤션이 있다.

User클래스 내부에는 구성한 데이터베이스에서 데이터를 쌓아 줄 columm을 만든다. 어떠한 기준으로 데이터베이스를 받을지 개발자가 모델링하기 나름이기에 현업에서는 모델링구조를 짜는 것이 엄청나게 중요해 보이지만 지금은 연습중이니 회원가입에서 필요한 기본적인 구성요소만 필드로 만들어 보겠다. 이메일, 패스워드, 휴대폰번호, 닉네임 이렇게 필드를 구성하였다.

이메일 필드에는 unique=True 라는 값을 주었는데 이메일 필드의 유니크의 기능은 중복되는 값의 input을 데이터베이스에 넣을 수 없게 만든다. 회원가입에 있어 이메일은 중복되어서는 안되기 때문이다.

나머지의 필드값들은 CharField(max_length=45)로 설정해주었는데 차필드는 글자를 받을 수 있는 필드이고 최대로 받을 수 있는 글자수를 45자로 제한해 놓았다.

Meta class는 데이터 베이스 내부의 테이블명을 정의해주는 기능이다.
테이블 이름을 users라고 정의해 주었다.

장고의 초기셋팅을 마쳤다면 마이그레이션 과정을 거쳐 데이터베이스 내에 테이블을 생성해주어야 하는데

$ python manage.py makemigrations
$ python manage.py migrate

명령어를 이용해 테이블을 만들어 준다.

views.py 작성

뷰스파이는 구성된 모델을 토대로 데이터를 어떤식으로 처리할지에 대한 논리를 작성하는 단이다.

import json, re

from django.views     import View
from django.http      import JsonResponse
from django.db.models import Q

from .models          import User

우선 코드의 맨위에 있는 import의 목록이다
먼저 http를 통해 받은 요청 정보(json)를 파이썬이 읽을 수 있는 형태로 변환해줄 수 있는 모듈인 json을 불러오고, json 형태로 응답(response) 해줄 수 있는 JsonResponse 모듈을 불러왔다.
그리고 우리가 쌓는 데이터의 기준이 되는 모델의 User도 import해온 것을 확인할 수 있다.
re는 정규식을 사용하기위해 Q는 장고내부의 조건문에서 or를 이용해서 코드를 정리하기 위해 import 하였다.

정규표현식이나 Q객체등을 설명하려면 이 포스팅의 본질을 흐리기에 나중에 따로 정리하도 하겠다. 그렇지만 포스팅 내용의 이해를 돕기위해 간단하게 설명하자면
정규표현식 : 특정한 규칙을 따르는 문자열의 집합
ex) 이메일은 @가 들어가야 한다
Q객체 : Django model ORM으로 where절에 or문을 사용할때 Q객체를 이용한다.
(장고의 조건문에서 or를 사용하기 위해 import했다고 생각하자)

SignupView

회원가입을 담당하는 SignupView클래스를 만들 것이다. 클래스 명을 정할 때는 내가 구현하고 있는 기능을 직관적으로 표현할 수 있는 단어를 택하는게 좋다. 그래야 다른사람이 이해하기 쉽고 무엇보다 나중에 내가 이해하기가 쉽다. 지금은 간단한 기능을 구현하니까 클래스가 몇개 안되겠지만 만약에 클래스가 1000개가 있다고 생각하면 클래스 명을 짓는 것은 굉장히 중요한 일일 것이다.

class SignupView(View):
    def post(self, request):

        try:
            user_email        = "(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
            user_phone_number = '^[0-9]{3}-[0-9]{4}-[0-9]{4}$'
            user_password     = '^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{8,18}$'

            data = json.loads(request.body)

            # email과 password의 값이 들어있지 않은 경우
            # email과 password의 KEY값이 일치하지 않을 경우 keyerror 리턴
            if '' == data['email']:
                return JsonResponse({'message': 'INVALID_EMAI'}, status=400)
            if '' == data['password']:
                return JsonResponse({'message': 'INVALID_PASSWORD'}, status=400)

post함수를 구성할 것인데 함수에서 매개변수로 받는 request는 클라이언트에서 요청하는 모든 정보가 담겨 있다.

이메일, 휴대폰번호, 패스워드는 정규식으로 검사하기위해 변수에 저장해놓았고
data변수는 프론트 단에서 요청한 정보를 파이썬에 읽을수 있게 디코딩하여 data변수에 할당한다는 의미이다.

변수 선언 아래의 조건문은 http로받은 이메일과 패스워드가 빈스트링이라면 INVALID오류를 리턴한다.

 # email과 password, phone_number가 정규표현식에 부합하지 않는 경우
            if not re.match(user_email, data['email']):
                return JsonResponse({'message': 'INVALID_EMAIL'}, status=400)

            if not re.match(user_phone_number, data['phone_number']):
                return JsonResponse({'message': 'INVALID_PHONE_NUMBER'}, status=400)

            if not re.match(user_password, data['password']):
                return JsonResponse({'message': 'INVALID_PASSWORD'}, status=400)

정규표현식에 부합하는지 검사하기 위해 변수를 선언해 놓고 re.match()함수를 사용하여고요청받은 값과 정규식이 부합하는지 검사후 부합하면 True를 부합하지 않으면 False를 리턴한다.

📌 조건문에서 굳이 if부정문을 사용한건 함수의 특성상 언제나 return이 가능하기 때문이다 만약 부정문을 사용하지 않았다면

if re.match(user_email, data['email']):
	continue
else:
	return JsonResponse({'message': 'INVALID_EMAIL'}, status=400

이처럼 code가 길어 진다.

이제 중복 검사를 할 것이다. 데이터베이스에 이미 회원 가입된 이메일이 있는데 누군가 중복되는 이메일로 가입을 하려고 한다면 오류 메시지를 출력을 해줘야 할 것이다.
보통의 웹사이트에서는 닉네임과 전화번호도 당연히 겹치면 안되기에 이메일,전화번호,닉네임이 이미 우리가 가진 데이터베이스에 들어와 있다면 OVERLAP_ERROR라는 메시지를 출력해 줄 것이다.

# 중복검사
            if User.objects.filter(
                Q(email=data['email'])|
                Q(phone_number=data['phone_number'])|
                Q(nickname=data['nickname'])).exists():
                return JsonResponse({'MESSAGE' : 'OVERLAP_ERROR'}, status=400)

            User.objects.create(
                email        = data['email'],
                password     = data['password'],
                phone_number = data['phone_number'],
                nickname     = data['nickname'],
            )

            return JsonResponse({'message': 'SUCCESS'}, status=201)

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

    def get(self, request):
        return JsonResponse({'message': 'SUCCESS'}, status=200)

클라이언트 단에서 보내온 요청을 filter함수를 사용하여 보내온 값을 추출하여 데이터 베이스에 존재하는지 exits함수를 이용하여 체크한다. 여기서 Q객체를 사용하였는데 만약에 Q객체를 사용하지 않았다면 정보 하나당 조건문을 하나씩 사용해야 하기 때문에 코드의 길이가 더 길어졌을 것이다.

보내온 값이 데이터베이스에 있는 값과 중복되지 않는다면 모든정보를 데이터 베이스에 생성하고 SUCCESS메시지를 리턴 해준다!!

그리고, 예외처리를 통해 키값이 혹시나 오타가 나거나 없는경우 KEY_ERROR를 리턴하도록 해주었다.

경로 설정

경로를 설정하기 위해서는 우선 최초에 만들어진 urls.py에서 들어온 정보를 해당 앱으로 가서 처리할 수 있게 만들어 줘야 한다.

# 경로 westagram/urls.py

from django.urls import path, include

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

코드의 최상단을 보면 path,inculde가 import되어있다.
path함수는 경로를 설정해주는 기능이 있고 뒤의 inculde함수는 인자값의 경로로 클라이언트의 요청을 보내주어 해당 앱에 처리를 맡긴다.여기서는 /user를 http에서 입력하여 들어온 것인데 거기서 받은 요청을 user.urls 즉, 유저app에있는 urls.py로 보내 처리를 하겠다는 뜻이다.

user/urls.py

from django.urls import path

from .views      import SignupView

urlpatterns = [
    path('', SignupView.as_view())
]

여기서도 위에 설명해놓은 로직이랑 비슷하다. 클라이언트 단에서 보내온 정보를 user앱의 views.py로 보내어 views.py에 있는 class의 함수의 코드 로직대로 해당요청을 처리하라는 뜻이다.
하지만,as_view()라는 함수는 처음보는데 애즈뷰 함수는 해당 클래스의 post,get,update,delete 함수등을 요청에서 판별하여 클래스 내의 정의된 post,get,update,delete 함수를 찾아가 요청을 실행하여 준다. 참 편한기능이 아닐수 없다.

profile
DONE IS BETTER THAN PERFECT

0개의 댓글