All Articles

django - 회원가입, 로그인, 댓글 기능 구현 실습 1

회원가입, 로그인, 댓글 작성 기능을 하는 엔드포인트를 구현하고 httpie로 회원가입, 로그인 테스트를 진행했다. 기능을 기반으로 앱을 분리해서 작업했기 때문에 회원가입, 로그인이 이루어질 users 앱을 생성하고, 댓글 작성 및 확인이 이루어질 comments 앱을 생성했다.

회원가입과 로그인 (user앱에서 진행)

먼저 models.py에서 데이터 저장에 앞서 필요한 데이터 테이블 틀을 잡았다.

from django.db import models

class Users(models.Model):
  # 가입 시 아이디(username)와 비밀번호(password) 정보를 받아야 하므로
  # user_data 테이블에 username열과 password열을 만들어줌
  username = models.CharField(max_length=50)
  password = models.CharField(max_length=300)

  class Meta:
    db_table = 'user_data'

그 다음 views.py에서 사용자가 회원가입 페이지와 로그인 페이지로 들어왔을 때 어떤 화면을 보여줄지 설정해준다.

import json
from django.views import View
from django.http import JsonResponse, HttpResponse
from .models import Users

# /users/로 들어왔을 때 출력되는 화면
class MainView(View):
  def get(self, request):
    return JsonResponse({'Welcome to':'Westagram', 'Sign-up':'/users/sign-up', 'Log-in':'/users/log-in'}, status=200)

# /users/sign-up/에서 액션에 따라 띄워줄 화면 설정
class SignUpView(View):
  # 데이터를 입력하는 것이므로 get이 아닌 post 메서드를 사용한다.
  def post(self, request):
    data = json.loads(request.body)
        
    # 유저가 입력한 데이터인 data['username']과 data['password']이
    # 각각 username과 password 열에 저장된다.
    try:
      Users(
        username = data['username'],
        password = data['password']
      ).save()

    # 에러가 발생하면 401코드와 함께 지정한 메시지를 띄운다.
    except:
      return JsonResponse({'message':'INVALID_ID'}, status=401)

    # 에러가 발생하지 않고 잘 작동하면 200코드와 함께 지정한 메시지를 띄운다.
    else:
      return JsonReponse({'message':'WELCOME'}, status=200)
    
  # /users/sign-up/을 호출했을 때 출력되는 화면
  def get(self, request):
    return JsonResponse({'Please':'Sign-up'}, status=200)

# /users/log-in/에서 액션에 따라 띄워줄 화면 설정
class LogInView(View):
  # 데이터를 입력하는 것이므로 get이 아닌 post 메서드를 사용한다.
  def post(self, request):
    data = json.loads(request.body)
    # sign-up과는 달리 데이터를 신규로 입력하는 것이 아니므로 .save()는 쓰지 않는다.
    Users(
      username = data['username'],
      password = data['password']
    )
    
    # 아이디가 유효하면 비밀번호가 유효한지 검사하고,
    # 아이디나 비밀번호가 유효하지 않다면 401코드와 함께 지정한 메시지를 띄운다.
    # 아이디와 비밀번호가 모두 일치한다면 200코드와 함께 지정한 메시지를 띄운다.
    try:
      if Users.objects.filter(username=data['username']).exists():
        user_id = Users.objects.get(username=data['username'])
        if data['password'] == user_id.password:
          return JsonResponse({'message':'WELCOME, ' + data['username']}, status=200)
        else:
          return JsonResponse({'message':'비밀번호가 틀립니다.'}, status=401)
      else:
        return JsonResponse({'message':'아이디가 없습니다.'}, status=401)
    except:
      return JsonResponse({'message':'INVALID_USER'}, status=401)

  # 로그인 정보를 받아서 입력한 유저의 정보만을 호출하고 싶었으나 아래처럼 하면 에러 발생
  def get(self, request):
    login_data = Users.objects.filter(username=data['username']).values()
    return JsonResponse({'user':list(login_data)}, status=200)

위에서 화면 별 액션을 설정해주었으므로 유저가 접속한 url과 views.py 파일을 연결해준다. 앱 디렉토리 안에는 urls.py가 없으므로 새로 만들어서 내용을 입력해준다.

from django.urls import path
from .views import MainView, SignUpView, LogInView

urlpatterns = [
  # /users/ 페이지에서는 MainView를 띄워준다.
  path('', MainView.as_view()),
  # /users/sign-up/ 페이지에서는 SignUpView를 띄워준다.
  path('sign-up/', SignUpView.as_view()),
  # /users/log-in/ 페이지에서는 LogInView를 띄워준다.
  path('log-in/', LogInView.as_view()),
]

/users/ 페이지와 /comments/ 페이지 호출이 왔을 경우 해당 페이지로 넘어갈 수 있도록 메인 디렉토리의 urls.py에서 연결해준다.

from django.contrib import admin
from django.urls import path, include

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

회원가입 테스트

데이터 입력(=회원가입)은 python shell과 sqlite3에서 진행했고, 테스트는 httpie로 진행했다.

# username과 password 입력하기 (가입)
>>> Users.objects.create(username='test1', password='test1234')

# 출력값(객체 생성)
<Users: Users object (1)>

sqlite에서 테이블에 잘 들어갔나 확인을 해보자.

select * from user_data;

# 출력값
id          username    password
----------  ----------  ----------
1           test1       test1234

같은 아이디로 가입을 시도하면 401코드 에러가 떠야한다. 이미 가입했던 test1 아이디로 가입 시도를 해보겠다.

http -v http://127.0.0.1:8001/users/sign-up/ username=test1 password=test1234

그럼 아래와 같은 결과값을 출력한다.

# request 메시지의 start line
POST /users/sign-up/ HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 45
Content-Type: application/json
Host: 127.0.0.1:8001
User-Agent: HTTPie/2.1.0

{
    "password": "test1234",
    "username": "test1"
}

# response 메시지의 start line
# 가입에 실패했으므로 에러코드 401 리턴
HTTP/1.1 401 Unauthorized
Content-Length: 25
Content-Type: application/json
Date: Sun, 14 Jun 2020 12:07:21 GMT
Server: WSGIServer/0.2 CPython/3.8.3
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

# 에러코드 401과 리턴하기로 설정한 메시지
{
    "message": "INVALID_ID"
}

로그인 테스트

테스트는 터미널 상에서 httpie로 진행했다.

http -v http://127.0.0.1:8001/users/log-in/ username=test1 password=test1234
# request 메시지의 start line
POST /users/log-in/ HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 45
Content-Type: application/json
Host: 127.0.0.1:8001
User-Agent: HTTPie/2.1.0

{
    "password": "test1234",
    "username": "test1"
}

# response 메시지의 start line
# 로그인에 성공했으므로 200 코드 리턴
HTTP/1.1 200 OK
Content-Length: 29
Content-Type: application/json
Date: Sun, 14 Jun 2020 12:10:59 GMT
Server: WSGIServer/0.2 CPython/3.8.3
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

# 200 코드와 함께 리턴하기로 설정한 메시지
{
    "message": "WELCOME, test1"
}

아이디나 비밀번호가 틀릴 때도 테스트 해보았다.

http -v http://127.0.0.1:8001/users/log-in/ username=test1 password=test123
# request 메시지의 start line
POST /users/log-in/ HTTP/1.1
# request 메시지의 headers
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 44
Content-Type: application/json
Host: 127.0.0.1:8001
User-Agent: HTTPie/2.1.0

# request 메시지의 body
{
    "password": "test123",
    "username": "test1"
}

# response 메시지의 start line
# 로그인에 실패했으므로 에러코드 401 리턴
HTTP/1.1 401 Unauthorized
# response 메시지의 headers
Content-Length: 27
Content-Type: application/json
Date: Sun, 14 Jun 2020 12:19:01 GMT
Server: WSGIServer/0.2 CPython/3.8.3
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

# response 메시지의 body
# 에러코드 401과 리턴하기로 설정한 메시지
{
    "message": "INVALID_USER"
}

코멘트 기능 실습 내용은 다음 글에 이어서 기록하겠다.