Python/Django기초

Django Backend Westargram 2장 (Mysql설정 및 회원가입 구현)

빈코더 2021. 9. 9. 22:05
728x90

Django Backend Westargram (Mysql설정 및 회원가입 구현)

1.Mysql 설정

Mysql설정을 해보자.

Mysql이 설치되었다는 가정하에 진행하도록 하겠다.

만약 설치가 안되어 있으면 .. 구글링 해보면 된다.

그럼 진행해보자.

기본적으로 접속 방법은 다음과 같다.

mysql -u root -p   <-- 명령어 입력( -u는 username, -p는 password이다.)
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 45
Server version: 8.0.22-0ubuntu0.20.04.3 (Ubuntu)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

이렇게 mysql에 접속하면 된다.

그리고 이제 1장에서 설정한 이름으로 DB를만들어준다.

mysql> create database westargram character set utf8mb4 collate utf8mb4_general_ci;
Query OK, 1 row affected (0.11 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| letsgo3            |
| mysql              |
| performance_schema |
| products           |
| starbucks          |
| sys                |
| westargram         |
+--------------------+
8 rows in set (0.00 sec)

위와 같이하면 Database가 생성이 된다.

character set은 언어설정을 위해서 필요한 옵션이다.

여기까지 하면 DB설정은 끝나는 것이다.

2. models.py and DB

이제 mysql을 납두고 새로 터미널창을 열어서 users/models.py파일을 열어주자.

vim users/models.py

1 from django.db import models

models.py를 설정하는 이유는 models.py에 만드는 클래스에 맞춰서 DB Table가 생성이 된다.

  • models.py : 클래스와 변수를 지정하면 데이터베이스와 연결되어(연결은 managers가 처리) 테이블과 필드로 매치됨

그렇기 때문에 아주 중요한 작업이다.

작성을 해야하는데.. 일단 DB Table을 어떻게 구성할지 생각을 해보자.

instargram과 비슷하게 구성하려면 필요한 정보는 일단

  • Email
  • Phone
  • Password
  • Name
  • Nickname
  • Create_Time
  • Update_Time
    위 7개의 필드가 필요하다고 생각이 든다.

그럼 7개의 필드가 들어간 class를 구성해보자.

from django.db import models

class Account(models.Model): <-- Class명의 첫글자는 무조건 대문자이다. 컨벤션이다.
    email        = models.EmailField()
    phone        = models.CharField(max_length=25)
    password        = models.CharField(max_length=100)
    name        = models.CharField(max_length=20)
    nickname            = models.CharField(max_length=20)
    create_at            = models.DateTimeField(auto_now_add=True)
    update_at            = models.DateTimeField(auto_now=True)

    def __Str__(self):
        return f'{self.name} : {self.email}'
    class Meta:
        db_table = 'accounts'

위 코드에 대해서 설명을 하자면

일단 Account라는 Class를 선언하고 위에서 말한 7가지의 필드를 설정해주고 각각 Field를 설정해 주었다.

  • max_length = 필드안에 들어갈수 있는 글자수 최대값 설정( max_length가 25면 25자까지 들어간다.)
  • DateTimeField = 날짜 및 시간 저장을 위한 필드
  • auto_now_add = 유저 생성시 자동으로 날짜 및 시간 저장 옵션
  • auto_now = 유저 정보 변경시 자동으로 날짜 및 시간 저장 옵션

그리고 __Str__은 파이썬 스페셜 메소드 또는 매직 메소드로 이미 파이썬 내부에서 만들어진 어떤 연산자들을 부모로부터 오버로딩해서 사용할 수 있도록 미리 만들어 둔 메소드의 집합을 의미

class안에서의 __Str__의 역할은 문자열 출력을 해주는 역할을한다.

그리고 class Meta는 DB에 Table저장할때 Table명이 'accounts'가 되도록 해준다.

설정을 안해주면 이상한 값이 붙어서 Table명이 생성된다.

여기까지 하면 models.py설정은 끝이다.

이제 Migrate를 해보자.

manage.py가 있는 위치로 이동해서 아래 명령어를 입력해준다.

python manage.py makemigrations  < -- 명령어 입력
Migrations for 'users':
  users/migrations/0001_initial.py
    - Create model Account

python manage.py migrate   < -- 명령어 입력
Operations to perform:
  Apply all migrations: contenttypes, sessions, users
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying sessions.0001_initial... OK
  Applying users.0001_initial... OK

테이블이 잘 생성이 됐는지도 확인해보자.

mysql> use westargram    <-- 입력
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;   <-- 입력
+-----------------------+
| Tables_in_westargram  |
+-----------------------+
| accounts              |
| django_content_type   |
| django_migrations     |
| django_session        |
+-----------------------+
4 rows in set (0.00 sec)

mysql> DESC accounts;   <-- 입력
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int          | NO   | PRI | NULL    | auto_increment |
| email     | varchar(254) | NO   |     | NULL    |                |
| phone     | varchar(25)  | NO   |     | NULL    |                |
| password  | varchar(100) | NO   |     | NULL    |                |
| name      | varchar(20)  | NO   |     | NULL    |                |
| nickname  | varchar(20)  | NO   |     | NULL    |                |
| create_at | datetime(6)  | NO   |     | NULL    |                |
| update_at | datetime(6)  | NO   |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

잘 생성이 됐다.

2. views.py

그럼 이제 views.py를 설정해보자.

views.py는 사용자 요청에 맞는 데이터 CRUD 로직 처리 작업을 해준다.

내 생각에는 가장 중요한놈이 아닐까? 라는 생각이든다.

views.py를 어떻게 작성하냐에 따라서 데이터의 CRUD작업이 효율적으로 이루어지냐, 비효율적으로 이루어지냐 차이가 난다.

물론 내코드도 이제 django 2주일차라 고칠부분이 많은점은 감안해서 따라와주면된다.

코드에 대한 피드백은 감사합니다 넙죽 절하고 받겠다.

회원가입을 구현할 예정이다.

view.py 작성하기전에 어떻게 작성할지에 대한 생각을 해보자.

  • 이메일과 핸드폰 번호,닉네임은 고유의 값이여야 한다. 즉 중복되는 정보가 없어야 한다.
  • 이메일에는 '@'와 '.' 포함되야 한다.
  • 비밀번호는 8글자 이상이여야 하고, 특수문자,영어,숫자가 최소 한개 이상은 들어가야 한다.
  • 위 모든게 해당되어야 계정을 생성할수 있다.

위 글을 참고하여 views.py를 생성해보자.

vim users/views.py

import json, re, traceback

from django.http            import JsonResponse  
from django.views           import View          
from django.core.exceptions import ValidationError
from django.db.models       import Q                                                                                                                
from .models                import Account      

MINIMUM_PASSWORD_LENGTH = 8  < -- 비밀번호 최소값을 저장해둔 전역변수

class SignUp(View):
    def post(self, request):
    data =json.loads(request.body)

잘라서 하는게 편할것 같아서 일단 윗부분 부터 작성을 했다.

import json

프론트와 통신을 통해서 데이터를 주고 받을때에는 json파일로 정보를 주고 받는다.

데이터의 송수신을 자바스크립의 객체로서 수행할 수 있게끔 하는 가벼운 문자열 데이터 표현식이다.

json파일은 딕셔너리 형식(key:value)으로 온다.

프론트에서 json 파일을 보낼때 '만국 공통 자료형'인 '문자열' 로 변환해서 전송한다.

그래서 django도 json 파일을 읽을수 있는것이다. 물론 가져와서 다시 python형식으로 변환시킨다.


import re

파이썬에서 정규식을 사용하기 위해서 re를 import를 해준다.

import traceback


from django.http import JsonResponse

HttpResponse의 subclass로, JSON-encoded response를 생성할수 있게 해준다.

JsonResponse는 response를 커스터마이징 하여 전달하고 싶을때,

http status code에 더하여 메세지를 입력해서 전달할 수 있다.


MINIMUM_PASSWORD_LENGTH = 8

패스워드 최소값을 저장해둔 전역변수이다.

추후 변경할일이 있으면 관리하기 쉽게 class 밖에다가 선언을 해줬다.

코드안에 숫자를 직접 대입하는것보다 이렇게 전역변수로 빼서 관리하는게 더 편하고 좋다는 말을 들었다.


data = json.loads(request.body)

클라이언트 즉 프론트로부터 날라온 requset를 json모듈러 읽어서 body부분을 data에 저장


이제 본문을 작성해보도록 하자.

def validate_email(email):
     pattern = re.compile('^.+@+.+\.+.+$')
     if not pattern.match(email):
         return JsonResponse({'message':'INVALID_EMAIL'}, status=400)

 # 패스워드 길이 검사
def validate_password(password):
     if len(password) < MINIMUM_PASSWORD_LENGTH:
         return JsonResponse({'message':'SHORT_PASSWORD'}, status=400)

 # 핸드폰 번호 검사        
def validate_phone(phone):
     pattern = re.compile('^[0]\d{9, 10}$')
     if not pattern.match(phone):
         return JsonResponse({'message':'USER_ALREADY_EXISTS'}, status=409)


 class SignUpView(View):
         def post(self, request):
             data =json.loads(request.body)

             try:                                             
                 email    = data.get('email', None)
                 password = data.get('password', None)          
                 name     = data.get('name', None)
                 nickname = data.get('nickname', None)
                 phone    = data.get('phone', None)


                 # KEY_ERROR check                            
                 if not(password and email and name and phone and nickname):
                     return JsonResponse({'message': 'KEY_ERROR'}, status=400)                  

                 # validation check                                                             
                 validate_email(email)
                 validate_password(password)                                                               
                 # unique check                                                                 
                 user = Account.objects.filter(Q(email=email) | Q(name=name) | Q(phone=phone))  
                 if not user:                                                                   
                     Account.objects.create(         
                     email    = email,                            
                     name     = name,
                     phone    = phone,
                     nickname = nickname,
                     password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
                     )
                     return JsonResponse({'message': 'SUCCESS'}, status=200)

                 return JsonResponse({'message': 'USER_ALREADY_EXISTS'}, status=409)

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

암호화를 위해서 2가지만 설치를 해주자.

pip install pyjwt bcrypt

이메일, 패스워드 길이, 핸드폰 번호 검사 함수를 만들어 주고,

편의를 위해 json데이터를 저장한 data에서 각각 필요한 값만 다시 저장을 해준다.

그리고 값이 다 제대로 들어왔는지 확인을 해준다.

그리고 값이 들어왔는지 확인하고 안들어왔으면 KEY_ERROR을 출력하도록 설정한다.

그 다음 위에서 만든 함수를 사용하여 email과 password의 검사를 해주고

검사가 다 끝나면 email, nickname, phone 중복을 확인해주고

중복이 없으면 내용을 DB에 넣도록 한다.

회원가입을 완료하면 200, 실패하면 409에러가 발생한다.

password는 암호화 한건데 저거는 다른글에 정리를 하도록 하겠다.

여기까지하면 끝이다.

이제 urls.py 파일을 설정해주자.

vim westargram/urls.py

from django.urls import path, include

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

include는 우리가 만든 users의 또는 앞으로 추가할 app들의 urls.py를 쉽게 관리를 하기 위해서 설정을 해준다.

클라이언트에서 뭔가 요청이 오면 project의 urls.py (ex: westargram 안에 있는 urls.py)를 찾게된다. 그럼 urls.py에서 요청에 맞게 include된 app으로 요청을 넘겨준다. 그럼 또 app에 있는 urls.py는 맞는 요청을 views.py에서 찾아서 처리를 하고 views.py에서 models.py로 요청을 보낸다. 이런 로직으로 클라이언트의 요청이 처리된다.

users안에도 urls.py를 만들어서 그것도 설정해주자.

from django.urls import path
from users.views import SignUpView

urlpatterns = [
         path('signup', SignUpView.as_view()),
]

위에서 설명했다시피 app안의 urls.py는 views.py의 class를 가리킨다.

as_view는 우리는 SignUpView에 post만 설정했지만 get,update,delete등 여러가지가 있는데 이걸 맞게 처리를 찾아서 처리를 해주는 역할이다.

이제 서버를 실행시켜주고 요청이 잘 처리되는지 확인해보자.

python .manage.py runserver

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
February 04, 2021 - 08:38:13
Django version 3.1.6, using settings 'westargram.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

서버를 켰고

새로운 터미널을 켜서 httpie를 설치해준다.

우분투
apt install httpie

맥
brew install httpie

설치를 해주고

다음과 같이 터미널에 입력을 해보자.

http POST 127.0.0.1:8000/users/signup email="test@gmail.com" name="빈코더" phone="01020304050" nickname="빈코더" password="123456781"

HTTP/1.1 200 OK
Content-Length: 22
Content-Type: application/json
Date: Thu, 04 Feb 2021 09:09:33 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "message": "SUCCESS"
}

SUCCESS가 안뜨면 어딘가에 설정이 제대로 안되어 있거나 urls.py를 제대로 설정을 안해줘서그렇다.

DB에도 잘 들어갔는지 확인해보자.

mysql> select * from accounts;
+----+----------------+-------------+--------------------------------------------------------------+-----------+-----------+----------------------------+----------------------------+
| id | email          | phone       | password                                                     | name      | nickname  | create_at                  | update_at                  |
+----+----------------+-------------+--------------------------------------------------------------+-----------+-----------+----------------------------+----------------------------+
|  1 | test@gmail.com | 01020304050 | $2b$12$UHOBo7nKHxaOZA90SVew6OrkUS6HewL2OMXYzCUJMdmqhfkkcT9Xu | 빈코더      | 빈코더     | 2021-02-04 09:09:33.009141 | 2021-02-04 09:09:33.009208 |
+----+----------------+-------------+--------------------------------------------------------------+-----------+-----------+----------------------------+----------------------------+

views.py에서 설정해놓은 예외처리를 발생시켜보자.

1. 아이디 중복 확인

http POST 127.0.0.1:8000/users/signup email="test@gmail.com" name="빈코더" phone="01020304051" nickname="빈코더1" password="123456781"


HTTP/1.1 409 Conflict
Content-Length: 34
Content-Type: application/json
Date: Thu, 04 Feb 2021 10:01:24 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "message": "USER_ALREADY_EXISTS"
}

2. nickname 중복 확인

ttp POST 127.0.0.1:8000/users/signup email="test1@gmail.com" name="빈코더" phone="01020304052" nickname="빈코더" password="123456781"

HTTP/1.1 409 Conflict
Content-Length: 34
Content-Type: application/json
Date: Thu, 04 Feb 2021 10:02:55 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "message": "USER_ALREADY_EXISTS"
}

3. 전화번호 중복 확인

http POST 127.0.0.1:8000/users/signup email="test1@gmail.com" name="빈코더" phone="01020304050" nickname="빈코더1" password="123456781"
HTTP/1.1 409 Conflict
Content-Length: 34
Content-Type: application/json
Date: Thu, 04 Feb 2021 10:04:57 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "message": "USER_ALREADY_EXISTS"
}

4. KEY_ERROR

http POST 127.0.0.1:8000/users/signup email="test1@gmailcom"  phone="01020304050" nickname="빈코더" password="123456781" 
HTTP/1.1 400 Bad Request
Content-Length: 24
Content-Type: application/json
Date: Thu, 04 Feb 2021 10:16:16 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "message": "KEY_ERROR"
}

에러가 잘 발생한다.

728x90

'Python > Django기초' 카테고리의 다른 글

Python Module & Packages  (0) 2021.09.09
Django의 코딩 스타일  (0) 2021.09.09
Django Backend Westargram 3장(로그인 구현)  (0) 2021.09.09
Django Backend Westargram 1장 (기초 설정)  (0) 2021.09.09
Django의 기초  (0) 2021.09.09