Django:제로부터 시작하는 인스타그램 만들기 - clone instagram #6

     

목차 - 2021.09.15 - [Study/python] - Django:제로부터 시작하는 인스타그램 만들기 - clone instagram 목차 

github - https://github.com/tkdlek11112/jinstagram

 

 

로그인/회원가입 만들기

 

이제 드디어 회원정보를 만들시기가 왔습니다. 어느 서비스에나 로그인과 회원가입은 필수죠. 최근에는 SNS 로그인으로 편하게 로그인을 할 수 있는데, 사용자에게는 편하지만 서버 쪽에서는 처리해줘야 하는 게 생각보다 많습니다 ㅋㅋ 여기서는 SNS 로그인은 사용하지 않고 단순하게 아이디와 비밀번호를 사용해서 회원가입과 로그인을 하도록 만들어보겠습니다. 아이디와 비밀번호만 받는 것이 단순하긴 단순한데 실제 서비스에 적용하기 위해서는 또 암호화 모듈이 필요하기 때문에 복잡해집니다. 저희는 실제 상용서비스를 만드는 것이 아니기 대문에 보안 문제는 스킵하고 가겠습니다.

 

 

모델 생성

피드를 만들기 위해 Feed모델을 만들었던것처럼 사용자 정보를 위해 User모델을 만들어야 합니다. 우리가 필요한 정보는 생각보다 간단합니다. 아이디 값으로 사용할 email, 실제 사용자 이름, 화면에 표시할 닉네임, 그리고 프로필 사진. 요정도만 있으면 우리가 만들 진스타그램에 표시할 사용자 정보 끝입니다.

 

일단 사용자모델을 만들기 전에 django app을 새로 만들어줍니다. feed를 관리하는 django app을 startapp content로 생성했던 게 기억나시나요? 사용자 관련 models.py와 views.py를 구분하여 관리하기 위해 user라는 django app을 새로 만들어줍니다. 

 

python manage.py startapp user

이제 user라는 폴더를 포함해서 content, jinstagram, media, templates 폴더가 구성되었습니다. 얼추 프로젝트 구성이 모양을 갖추고 있는 느낌이네요. 앱을 추가하고 jinstagram/settings.py에 있는 INSTALLED_APP에 추가하는 걸 잊으시면 안 됩니다.

 

# jinstagram/settings.py

INSTALLED_APPS = [
    ...
    'content',
    'user'
]

 

바로 모델을 만들어볼까요? 다만 사용자 관련 모델을 만드는데 중요한 사항이 하나 있습니다. 원래는 django 프로젝트를 시작하면서 가장 먼저 사용자 모델을 어떻게 사용할지를 결정해야 하는데요, 왜냐하면 장고에서 기본적으로 제공해주는 사용자 모델이 있기 때문에, 이 모델을 사용할지, 아니면 새로 만들어서 사용할지 결정해야 합니다. 

 

그냥 새로 만들어서 사용하면 되지 않나?라고 생각할 수 있는데 장고에서 기본적으로 제공해주는 사용자 모델은 추가적인 기능들을 제공해주는데 예를 들어서 비밀번호 암호화나 세션 체크 등입니다. 일반적으로는 장고에서 제공하는 유저 모델을 그대로 사용하거나 커스텀해서 사용하는데요, 저희도 커스텀 유저 모델을 사용하도록 하겠습니다.

 

# ~/user/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser


# Create your models here.
class User(AbstractBaseUser):
    name = models.CharField(max_length=30, blank=True, null=True)
    email = models.EmailField(verbose_name='email', max_length=100, blank=True, null=True, unique=True)
    user_id = models.CharField(max_length=30, blank=True, null=True)
    thumbnail = models.CharField(max_length=256, default='default_profile.jpg', blank=True, null=True)

    USERNAME_FIELD = 'id'
    REQUIRED_FIELDS = ['user_id']

    def __str__(self):
        return self.user_id

    @property
    def is_staff(self):
        return self.is_admin

    class Meta:
        db_table = 'users'

 

장고에서 제공하는 기본적인 사용자 모델을 사용하기 위해서는 AbstractBaseUser라는 클래스를 상속받으면 됩니다. 이전에 다른 모델 만들 때는 class 모델명(models.Model)이라고 한 반면, 사용자 모델은 class User(AbstractBaseUser)라고 되어있습니다. 일반 모델이 아니라 AbstractBaseUser라는 장고에서 제공하는 유저 모델을 가져와서 사용하겠다는 뜻입니다.

 

이 사용자 모델을 사용했을 때 또 다른 점은, USERNAME_FIELD와 REQUIRED_FIELDS라는 것을 써줬다는 점입니다. USERNAME_FIELD = 'id'는 사용자의 이름값을 'id'필드로 사용한다는 뜻이고, REQUIRED_FIELDS는 사용자 데이터를 만들 때 꼭 필요한 데이터 필드를 말합니다.

 

모델을 만들었으니 python manage.py makemigrations과 migrate를 해주어야 하는데, migrate 하기 전에 db.sqlite3 파일을 지우고 해 줍니다. 지우는 이유는 이전에 migrate를 할 때 auth_user라는 테이블이 만들어졌을 텐데 이게 django의 기본 유저 테이블 역할을 하고 있기 때문에 우리가 만든 AbstractBaseUser를 상속한 User가 제 역할을 하지 못합니다. 

 

즉- AbstractBaseUser를 사용할 거면 프로젝트 가장 처음에 해야 고생 안 한다는 점~!

 

여기서 주의할 점은 마이 그레이트를 하기 전에 settings.py에서 우리가 만든 User모델이 Django기본 유저 모델이라는 것을 명시해줘야 합니다.

 

 

# ~/jinstagram/settings.py

AUTH_USER_MODEL = 'user.User'

 

settings.py에 AUTH_USER_MODEL = 'user.User'라고 써줍니다. 여기서 user는 우리가 만든 앱 이름 'user'이고 뒤에 User는 우리가 만든 모델 이름 'User'입니다.

 

이제 python manage.py makemigrations, migrate를 해줍니다. 그럼 원래는 auth_user 테이블이 있었을 텐데 대신 users라는 테이블이 생겼을 겁니다.

 

users 테이블

 

여기서 특이한 점은 저희가 password라는 필드를 따로 정의해주지 않았는데도 필드가 있다는 점입니다. 이게 AbstractBaseUser를 상속받아서 사용하면 좋은 점 중에 하나인데, password 필드가 자동으로 암호화되어서 저장되기 때문에 저희가 따로 암호화 로직을 넣어줄 필요가 없습니다. 개꿀~

 

 

화면 만들기

 

이제 로그인과 회원가입을 할 수 있는 화면을 만들어야 합니다. 화면은 templates폴더에 html 파일로 만들건대, user라는 앱을 새로 만들고 user앱 안에 model을 만들어줬던 것처럼 template도 app단위로 분리하기 위해서 templates 폴더 아래 user라는 폴더를 만들고 거기에 login.html과 join.html을 만듭니다.

 

templates안에도 app단위로 분리

 

 

<!-- ~/templates/user/join.html -->
<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">

    <!-- jquery 사용하기 위해 -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>


    <title>Jinstagram login</title>
</head>
<style>
    .floating_form {
        margin: 0px 30px;
    }

    .floating_label {
        margin-top: -4px;
        font-size: 14px;
    }

    .floating_input {
        height: 50px !important;
        padding-top: 20px !important;
        font-size: 14px !important;
    }

</style>
<body style="background-color: #FAFAFA;height: 100%">
<div style="font-size: 14px;text-align: center;width: 100%;min-height: 100vh;display: flex; flex-direction: row; align-items: center; justify-content: center">
    <div>
        <div class="mb-3" style="background-color: white; width: 350px; height: 480px; border: 1px solid rgba(0, 0, 0, 0.18);">
            <div style="display: flex;align-items: center;justify-content: center">
                <img style="height: 50px; object-fit: contain; margin: 30px 0"
                     src="https://www.instagram.com/static/images/web/mobile_nav_type_logo-2x.png/1b47f9d0e595.png">
            </div>
            <div style="font-size:17px; font-weight:600; line-height: 20px; text-align: center; color: rgba(142,142,142,1); margin: 0 40px 20px">
                친구들의 사진과 동영상을 보려면 가입하세요.
            </div>
            <div class="form-floating mb-2 floating_form">
                <input type="email" class="floating_input form-control" id="floatingEmail"
                       placeholder="name@example.com">
                <label for="floatingEmail" class="floating_label">이메일 주소</label>
            </div>
            <div class="form-floating mb-2 floating_form">
                <input type="text" class="floating_input form-control" id="floatingName" placeholder="홍길동">
                <label for="floatingName" class="floating_label">성명</label>
            </div>
            <div class="form-floating mb-2 floating_form">
                <input type="text" class="floating_input form-control" id="floatingUserId" placeholder="hong">
                <label for="floatingUserId" class="floating_label">사용자 이름</label>
            </div>
            <div class="form-floating mb-3 floating_form">
                <input type="password" class="floating_input form-control" id="floatingPassword" placeholder="Password">
                <label for="floatingPassword" class="floating_label">비밀번호</label>
            </div>
            <div class="floating_form mb-3">
                <button id="button_join"  type="button" class="btn btn-primary" style="width: 100%"> 가입 </button>
            </div>
        </div>
        <div style="background-color: white; width: 350px; height: 70px; border: 1px solid rgba(0, 0, 0, 0.18);">
            <div style="margin-top: 25px">
                계정이 있으신가요? <a href="{% url 'login' %}" style="font-weight: bold; color: cornflowerblue;text-decoration: none; cursor: pointer">가입하기</a>
            </div>
        </div>
    </div>
</div>


<!-- Optional JavaScript; choose one of the two! -->
<script>
    $('#button_join').on('click',()=>{
        console.log('클릭했다.');
        let email = $('#floatingEmail').val();
        let name = $('#floatingName').val();
        let user_id = $('#floatingUserId').val();
        let password = $('#floatingPassword').val();
        console.log('이멜 :' + email + ', 이름 :'  + name + ', 사용자이름 :'  +  user_id + ', 비밀번호 :'  +  password);

        $.ajax({
            url: "/user/join",
            data: {
                email: email,
                password: password,
                user_id: user_id,
                name: name
            },
            method: "POST",
            dataType: "json",
            success: function (data){
                alert(data.message);
                location.replace('{% url 'login' %}');
            },
            error:function (request, status, error){
                let data = JSON.parse(request.responseText);
                console.log(data.message);
                alert(data.message);
            }
        });


    });
</script>

<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ"
        crossorigin="anonymous"></script>

<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js" integrity="sha384-W8fXfP3gkOKtndU4JGtKDvXbO53Wy8SZCQHczT5FMiiqmQfUpWbYdTil/SxwZgAN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
-->
</body>
</html>
<!-- ~/templates/user/login.html -->
<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">

    <!-- jquery 사용하기 위해 -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    <title>Jinstagram login</title>
</head>
<style>
    .floating_form {
        margin: 0px 30px;
    }

    .floating_label {
        margin-top: -4px;
        font-size: 14px;
    }

    .floating_input {
        height: 50px !important;
        padding-top: 20px !important;
        font-size: 14px !important;
    }

</style>
<body style="background-color: #FAFAFA;height: 100%">
<div style="font-size: 14px;text-align: center;width: 100%;min-height: 100vh;display: flex; flex-direction: row; align-items: center; justify-content: center">
    <div>
        <div class="mb-3" style="background-color: white; width: 350px; height: 380px; border: 1px solid rgba(0, 0, 0, 0.18);">
            <div style="display: flex;align-items: center;justify-content: center">
                <img style="height: 50px; object-fit: contain; margin: 30px 0"
                     src="https://www.instagram.com/static/images/web/mobile_nav_type_logo-2x.png/1b47f9d0e595.png">
            </div>
            <div class="form-floating mb-2 floating_form">
                <input type="email" class="floating_input form-control" id="floatingEmail"
                       placeholder="name@example.com">
                <label for="floatingEmail" class="floating_label">이메일 주소</label>
            </div>
            <div class="form-floating mb-3 floating_form">
                <input type="password" class="floating_input form-control" id="floatingPassword" placeholder="Password">
                <label for="floatingPassword" class="floating_label">비밀번호</label>
            </div>
            <div class="floating_form mb-3">
                <button id="button_login" type="button" class="btn btn-primary" style="width: 100%"> 로그인</button>
            </div>
            <div class="mb-2" style="display: flex; align-items: center; justify-content: space-between">
                <hr style="border:1px silver;margin-left: 30px;width: 100px">
                또는
                <hr style="border:1px silver;margin-right: 30px;width: 100px">
            </div>
            <div style="font-weight: bold; color: royalblue">
                테스트로 로그인 (둘러보기)
            </div>
        </div>
        <div style="background-color: white; width: 350px; height: 70px; border: 1px solid rgba(0, 0, 0, 0.18);">
            <div style="margin-top: 25px">
                계정이 없으신가요? <a href="{% url 'join' %}" style="font-weight: bold; color: cornflowerblue; text-decoration: none; cursor: pointer">가입하기</a>
            </div>
        </div>
    </div>


</div>


<!-- Optional JavaScript; choose one of the two! -->
<script>
    $('#button_login').on('click', ()=>{
        let email = $('#floatingEmail').val();
        let password = $('#floatingPassword').val();

        $.ajax({
            url: "/user/login",
            data: {
                email: email,
                password: password
            },
            method: "POST",
            dataType: "json",
            success: function (data){
                location.replace('{% url 'main' %}');
            },
            error:function (request, status, error){
                let data = JSON.parse(request.responseText);
                console.log(data.message);
                alert(data.message);
            }
        });
    });
</script>
<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ"
        crossorigin="anonymous"></script>

<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js" integrity="sha384-W8fXfP3gkOKtndU4JGtKDvXbO53Wy8SZCQHczT5FMiiqmQfUpWbYdTil/SxwZgAN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
-->
</body>
</html>

 

bootstrap을 최대한 활용해서 로그인 화면을 만들어줍니다. 

 

로그인과 회원가입 화면은 거의 비슷한데, 로그인 같은 겨우 id와 password 2개만 입력하고, 회원가입인 경우 닉네임이나 이름 같은 값을 입력하기 때문에 로그인보다 입력하는 게 많습니다.

 

로그인 화면
회원가입 화면

 

 

로그인과 회원가입에서 각각 ajax를 이용해 /user/login과 /user/join을 호출하는데, 아직 해당하는 기능을 만들지 않았습니다. urls.py와 views.py를 이용해 회원가입과 로그인 기능을 만들어봅시다.

 

 

 

views.py 만들기

MVC패턴에서는 Controller인데 Django에 MTV패턴에서는 View입니다.

 

views.py 역시 새로 만든 user 앱 안에 views.py에 만들어줍니다.

 

from django.shortcuts import render
from rest_framework.views import APIView
from .models import User
from django.contrib.auth.hashers import make_password, check_password
from rest_framework.response import Response
from uuid import uuid4
import os
from jinstagram.settings import MEDIA_ROOT


class Login(APIView):
    def get(self, request):
        return render(request, 'user/login.html')

    def post(self, request):
        email = request.data.get('email', None)
        password = request.data.get('password', None)
        if email is None:
            return Response(status=500, data=dict(message='이메일을 입력해주세요'))

        if password is None:
            return Response(status=500, data=dict(message='비밀번호를 입력해주세요'))

        user = User.objects.filter(email=email).first()

        if user is None:
            return Response(status=500, data=dict(message='입력정보가 잘못되었습니다.'))

        if check_password(password, user.password) is False:
            return Response(status=500, data=dict(message='입력정보가 잘못되었습니다.'))

        request.session['loginCheck'] = True
        request.session['email'] = user.email

        return Response(status=200, data=dict(message='로그인에 성공했습니다.'))


class Join(APIView):
    def get(self, request):
        return render(request, 'user/join.html')

    def post(self, request):
        password = request.data.get('password')
        email = request.data.get('email')
        user_id = request.data.get('user_id')
        name = request.data.get('name')

        if User.objects.filter(email=email).exists() :
            return Response(status=500, data=dict(message='해당 이메일 주소가 존재합니다.'))
        elif User.objects.filter(user_id=user_id).exists() :
            return Response(status=500, data=dict(message='사용자 이름 "' + user_id + '"이(가) 존재합니다.'))

        User.objects.create(password=make_password(password),
                            email=email,
                            user_id=user_id,
                            name=name)

        return Response(status=200, data=dict(message="회원가입 성공했습니다. 로그인 해주세요."))

 

먼저 회원가입부터 보자면, 기본적인 개념은 간단합니다. 클라이언트로부터 회원정보를 받아서 DB에 넣으면 됩니다. 하지만 그전에 해줘야 하는 작업이 있는데, 바로 중복 막기입니다. 아마 여러분들도 회원가입을 할 때 항상 만들고자 했던 id가 존재해서 만들지 못한 경험을 해보셨을 겁니다. 우리도 그 체크를 해줘야 하는데, 구현하는 방법이 여러 가지입니다.

 

가장 쉬운 방법은 DB table에 해당 칼럼을 유니크하게 만들어주는 방법입니다. 저희는 email이 id이기 때문에 email 컬럼을 unique로 설정해주면, DB에 저장할 때 DB가 자동으로 에러를 발생시킵니다. 이 방법은 저희가 따로 코드를 넣어줄 필요 없어 DB 테이블 스키마만 설정해주면 되기 때문에 아주 심플한데, 운영적인 관점에서 보면 상당히 리스크가 있을 수 있습니다. 왜냐하면 DB에 Create하지도 않을 쓸데없는 데이터를 가지고 Application이 DB에 접속한다는 것이 의미 없기 때문이죠. 이미 mychew라는 id가 있는데 누군가가 mychew를 계속 만들기를 시도한다면, Application 서버는 mychew라는 id를 만들기 위해 계속해서 DB에 연결을 시도할 겁니다. 그렇게 되면 DB에 connection 부하가 생길 수 있고, 다른 DB 작업에 영향을 줄 수도 있습니다.

 

이런 것을 방지하기 위해 Application에서 중복을 막는 방법이 있습니다. 먼저 input으로 들어온 id값이 DB에 있는지 select 해보고 없으면 create 하는 방법입니다. 이렇게 하면 만들지도 않을 데이터를 가지고 DB에 접속할 일은 없지요. 하지만 select를 한번 해야 하기 때문에 DB에 접속하긴 해야 합니다. 여기서도 DB에 한번 접근하는데 이건 괜찮을까요?

 

이럴 때는 몇 가지 트릭을 써서 문제를 해결할 수 있습니다. 일단 기본적으로 select는 읽기 작업이기 때문에 DB에 lock을 걸지 않습니다. DB lock이란 특정 테이블에 접근했을 때 자신 말고 다른 곳에서 접근할 수 없게 막는 것을 말합니다. 따라서 A라는 테이블에 create문이나 update문을 하게 되면 다른 곳에서는 A라는 테이블에 접근할 수 없습니다. 이건 아주 극단적인 예이긴 한데요, 대부분 row lock이나 field lock으로 lock의 범위를 작게 해서 같은 테이블이라도 접근할 수 있도록 열어주는 경우가 많습니다. 너무 데이터베이스 적인 내용이라 궁금하신 분들은 데이터베이스 이론을 좀 더 파보시면 좋을 것 같습니다.

 

아무튼 create를 할 때 lock이 걸리니 create를 이용한 DB 접근을 최소화하는 게 좋습니다. 반면 select 쿼리는 DB lock을 걸지 않기 때문에 create보다는 자유롭습니다. 따라서 무작정 create로 DB에 접속해서 생성할 수 있을지 없을지 판단하기보다는, 먼저 select로 데이터를 가져와서 데이터를 비교하는 것이 더 안전한 방법입니다.

 

위 소스에서는. exists()라는 함수를 이용해 중복을 체크하고 있습니다. User.objects.filter(email=email). exists()라는 코드는 input email과 동일한 email의 데이터가 있으면 True, 없으면 False를 반환합니다. 마찬가지로 User.objects.filter(user_id=user_id). exists()는 user_id가 겹치는 게 있으면 Ture, 없으면 False를 반환합니다. 사실 사용자 이름은 name이고 user_id는 닉네임인데, 메시지를 사용자 이름이라고 해서 좀 헷갈리네요 ㅋㅋ

 

아 마지막으로 중요한 건 User.objects.create를 할 때, password를 암호화한다는 점입니다. password=password가 아니라 password=make_password(password)라고 적힌 부분에 주목하세요.

 

 

로그인의 경우가 사실 개념이 더 쉬운데 코드는 더 깁니다. 기본 개념은 client로부터 id와 password를 받고, id로 User정보를 찾은 다음 password가 동일한지 비교해서 맞으면 로그인 성공, 틀리면 실패하는 로직입니다. 하지만 이렇게 password를 비교하는 로직까지 가기 전에 수많은 예외처리가 필요합니다.

 

일단 input으로 들어온 값이 Null이거나 비어있는지 체크해야 합니다. 값이 제대로 들어왔다면 User테이블에 input으로 들어온 id를 가진 데이터가 있는지 체크해야합니다. 만약 없다면 회원가입을 하지 않았거나 id를 잘 못 입력한 것이죠.

 

User 테이블에서 데이터까지 찾았다면 이제 본격적으로 password를 검증할 차례입니다. 우리는 password를 암호화해서 저장했기 때문에 그냥 password == password를 하게 되면 항상 False가 나옵니다. 이럴 때는 check_password라는 함수를 사용해서 암호회 된 password와 input password를 비교할 수 있습니다.

 

password까지 통과했다면 로그인 성공입니다. 로그인했을 경우 로그인 정보를 session에 저장하기 위해 request.session에 데이터를 넣어줍니다. 이렇게 session에 데이터를 넣어 놓으면 클라이언트와 서버가 연결이 끊길 때까지 session에 담은 데이터를 사용할 수 있습니다.

 

 

urls.py 수정하기

 

이제 마지막으로 urls.py에서 views.py에서 만든 class들에게 url을 매핑해주는 작업만 남았습니다.

 

# ~/user/urls.py

from django.urls import path
from .views import Login, Join, LogOut, UpdateProfile


urlpatterns = [
    path('login', Login.as_view(), name='login'),
    path('join', Join.as_view(), name='join'),
]

 

자 이제 모든 준비가 끝났습니다.

 

 

이제 직접 화면에 접속해서 회원가입과 로그인을 해봅시다.

 

회원가입
로그인

 

DB에 저장

 

 

실제 DB에 저장이 잘 되었는지 확인해보고 다음 강의로 고고~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY