일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- Github
- Google Spreadsheet
- array
- Python
- Google Excel
- matplotlib
- Redshift
- c#
- math
- Kotlin
- PySpark
- Tkinter
- PostgreSQL
- dataframe
- 파이썬
- google apps script
- Apache
- SQL
- Excel
- Mac
- PANDAS
- Java
- GIT
- gas
- django
- list
- numpy
- hive
- string
- Today
- Total
달나라 노트
Python django project 1 - 게시판 만들기 ch.8 : 로그인 본문
Python django project 1 - 게시판 만들기 ch.8 : 로그인
CosmosProject 2020. 12. 20. 21:47
지난 챕터에서 회원가입을 구현했으니 이번엔 로그인을 만들어봅시다.
마찬가지로 MTV 순서로 코딩을 진행할겁니다.
일단 회원가입이건 로그인이건 모두 user app에서 구현할 것이기때문에 user app에 있는 MTV를 한번 봐봅시다.
일단 Model입니다.
로그인을 할 때 필요한 정보는 유저이름(or 유저 ID), 비밀번호입니다.
근데 이 정보는 이미 pro/app/user/models.py에 ModelUser라는 이름의 class로 구현해놨죠.
따라서 따로 Model을 다시 생성할 필요는 없습니다.
그럼 이제 Template입니다.
로그인을 위한 html 파일은 존재하지 않으니 새로 만들어줘야겠네요.
pro/app/user/templates에 user_login.html 이라는 파일을 하나 만들고 아래처럼 작성합니다.
{% extends 'base.html' %}
{% block body %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>User Login</h1>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<form method="POST" action=".">
{% csrf_token %}
<span>{{ res_data.errmsg_values }}</span>
<span>{{ res_data.errmsg_password }}</span>
<span>{{ res_data.errmsg_username }}</span>
{{ res_data.errmsg_}}
<div class="form-group">
<label for="username">User id</label>
<input id="username" class="form-control" type="text" name="username" placeholder="User id"/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input id="password" class="form-control" type="password" name="password" placeholder="Password"/>
</div>
<div class="row mt-5">
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/'">Home</button>
</div>
<div class="col-6">
<button type="submit" class="btn btn-primary btn-block">Submit</button>
</div>
</div>
</form>
</div>
</div>
{% endblock %}
위 코드를 한번 잘 봐봅시다.
이전 챕터에서 했던 회원가입의 html파일과 상당히 비슷하지않나요?
회원가입 html과 다른 점은 비밀번호 확인을 위한 re_password input이 사라진 것이 login html이라는 것입니다.
그 이유는 생각해보면 당연합니다.
회원가입이나 로그인이나 필요한 정보가 비슷하기 때문이죠.
그래서 사실 위 코드를 새로 작성할 필요없이 user_register.html 파일을 복사해서 이름만 바꿔쓰면 상당히 편하게 코딩을 할 수 있겠죠.
그러면 다음 step은 View를 코딩하는 것입니다.
pro/app/user/views.py에 다음과 같은 내용을 추가합시다.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
def view_user_login(request):
if request.method == 'GET':
return render(request, 'user_login.html')
elif request.method == 'POST':
username = request.POST.get('username', None)
password = request.POST.get('password', None)
res_data = {}
if not(username and password):
res_data['errmsg_values'] = 'All values are required.'
else:
try:
modeluser = userapp_model.ModelUser.objects.get(username=username)
except userapp_model.ModelUser.DoesNotExist:
res_data['errmsg_username'] = 'The user cannot be found.'
else:
if check_password(password, modeluser.password):
request.session['login_userkey'] = modeluser.id
request.session['login_username'] = modeluser.username
return redirect('/')
else:
res_data['errmsg_password'] = 'Password is wrong.'
dict_render = {
'res_data': res_data
}
return render(request, 'user_login.html', dict_render)
기본적인 틀은 역시나 회원가입에 사용되었던 view의 함수와 비슷합니다.
def view_user_login(request):
...
else:
try:
modeluser = userapp_model.ModelUser.objects.get(username=username)
except userapp_model.ModelUser.DoesNotExist:
res_data['errmsg_username'] = 'The user cannot be found.'
else:
if check_password(password, modeluser.password):
request.session['login_userkey'] = modeluser.id
request.session['login_username'] = modeluser.username
return redirect('/')
else:
res_data['errmsg_password'] = 'Password is wrong.'
...
다만 이 부분을 한 번 봐봅시다.
값이 모두 존재할 경우 else: 블록이 실행됩니다.
def view_user_login(request):
...
try:
modeluser = userapp_model.ModelUser.objects.get(username=username)
...
그리고 위처럼 입력된 username을 가진 데이터(모델에 존재하는 하나하나의 행(row)이라고 생각하면 쉽습니다.)가 user model에 존재하는지 체크해봅니다.
def view_user_login(request):
...
except userapp_model.ModelUser.DoesNotExist:
res_data['errmsg_username'] = 'The user cannot be found.'
...
근데 만약 입력한 username을 가진 데이터를 model에서 찾을 수 없다면?
로그인을 하려는데 입력한 username이 model에 없다면 당연히 로그인에 실패해야겠죠.
그래서 위처럼 유저를 찾을 수 없다는 메세지를 넣습니다.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
def view_user_login(request):
...
else:
try:
modeluser = userapp_model.ModelUser.objects.get(username=username)
...
else:
if check_password(password, modeluser.password):
request.session['login_userkey'] = modeluser.id
request.session['login_username'] = modeluser.username
return redirect('/')
else:
res_data['errmsg_password'] = 'Password is wrong.'
...
그리고 만약 입력된 username을 가진 행(row)이 model에 존재한다면?
당연히 입력받은 내용이 model에 저장된 user 정보와 동일한지 봐야겠죠.
그래서 저는 django에서 제공하는 check_password를 사용했습니다.
check_password(입력받은 비밀번호, model에 저장된 비밀번호)
check_password는 위처럼 사용하는데 입력받은 비밀번호와 model에 저장된 비밀번호를 비교해줍니다.
만약 두 값이 다르다면 False이므로 res_data에 비밀번호가 잘못되었다는 메세지를 저장합니다.
만약 두 값이 같다면 True이므로 session에 내용을 저장하는 과정을 거칩니다.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
def view_user_login(request):
...
request.session['login_userkey'] = modeluser.id
request.session['login_username'] = modeluser.username
return redirect('/')
...
그럼 여기서 세션이란게 무엇인지를 알아야합니다.
복잡한 설명은 제쳐두고 간단하게 말하자면,
사용자(좀 더 정확하게 말하면 웹 브라우저)가 요청하는 어떤 정보들을 브라우저를 종료할 때 까지 저장시켜두는 것입니다.
위 상황을 예로들면 사용자의 요청(request)에 대한 session의 login_userkey라는 key에다가 로그인을 요청한 사용자의 primary key(modeluser.id)를 value로 연결시켜 저장합니다.
마찬가지로 사용자의 요청(request)에 대한 session의 login_username라는 key에다가 로그인을 요청한 사용자의 primary key(modeluser.username)를 value로 연결시켜 저장합니다.
django에선 session에 정보를 저장하거나 빼낼 때 이렇게 dictionary의 형태로 사용할 수 있습니다.
그러면 위와 같은 session이 왜 필요한것일까요?
아직 진행하진않았지만 추후 코딩할 게시판을 예로 들어봅시다.
보통 게시글을 작성하기 위해선 로그인을 해야합니다. 그리고 로그인을 한 후에 게시글을 작성하면 그 게시글의 작성자는 자연스럽게 로그인한 유저가 되는것이죠.
그러면 게시글 작성을 위해선 두 가지를 체크해야합니다.
1. 현재 사용자가 로그인상태인가?
2. 로그인해있다면 어떤 사용자인가?
위 내용을 바로 session에서부터 가져옵니다.
로그인을 하면 session에 로그인한 유저의 정보를 저장하게되고, 추후 로그인한 사용자에 대한 정보가 필요할 때 위처럼 session에서 로그인 유저의 정보를 가져와서 사용하는 것이죠.
tip. 세션과 쿠키의 차이점은?
한 가지 별도로 쿠키에 대해 아주 간단하게 얘기해봅시다.
브라우저를 쓰다 보면 쿠키삭제라는 것을 해본 분들이 많을겁니다.
생각해보니 이 쿠키도 브라우저를 사용하면서 어떤 정보가 저장되어 쌓이는 그런 느낌인거같은데 그러면 세션과 뭐가 다를까요?
세션은 유저의 요청등을 '서버'에 저장합니다.
반면에 쿠키는 '유저의 컴퓨터 메모리'에 저장한다는 차이가 있죠.
이제 다시 위 view 코드로 돌아오면, 로그인 시에 입력된 비밀번호가 model에 저장된 해당 username의 비밀번호와 동일하다면 session에 로그인한 유저의 정보를 저장하고, home으로 redirect합니다.
이제 login url을 연결해줘야겠죠.
pro/app/user/urls.py를 아래처럼 수정합시다.
from django.contrib import admin
from django.urls import path, include
from . import views as userapp_view
urlpatterns = [
path('user_register/', userapp_view.view_user_register),
path('user_login/', userapp_view.view_user_login)
]
그리고 pro/app/user/templates/home.html에 login버튼을 아래처럼 만들어봅시다.
{% extends 'base.html' %}
{% block body %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>Home</h1>
</div>
</div>
<div class="row mt-5">
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_register/'">Register</button>
</div>
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_login/'">Login</button>
</div>
</div>
{% endblock %}
그리고 runserver를 하여 127.0.0.1:8000 주소로 들어가봅시다.
그러면 위처럼 로그인 버튼이 생겼죠.
그리고 login 버튼을 누르면 로그인화면으로 잘 이동됩니다.
이제 로그인을 진행해봅시다.
값을 입력하지 않았을 때의 에러메세지도 잘 뜨는걸 알 수 있구요.
비밀번호가 틀렸을 때 나오는 에러메세지도 볼 수 있습니다.
그리고 제대로 값을 입력하여 로그인에 성공했을 때 Home화면으로 돌아오는 것도 확인가능합니다.
근데 좀 이상하죠.
로그인을 성공해서 홈 화면으로 돌아왔는데 로그인이 된건지 아닌지 보이는 것이 없습니다.
이를 위해 Home화면을 수정해봅시다.
로그인을 했을 때 로그인 사용자의 정보를 출력해줄것이며, 또 로그인 상태일 때는 Logout 버튼이 보이게 해봅시다.
{% extends 'base.html' %}
{% block body %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>Home</h1>
</div>
</div>
{% if request.session.login_userkey %}
<div class="row mt-5">
<div class="col-12">
<h4>Login user key : {{ request.session.login_userkey }}</h4>
<h6>Login user name : {{ request.session.login_username }}</h6>
</div>
</div>
{% else %}
<div class="row mt-5">
<div class="col-12">
<h4>Not Logined</h4>
</div>
</div>
{% endif %}
{% if request.session.login_userkey %}
<div class="row mt-5">
<div class="col-12">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_logout/'">Logout</button>
</div>
</div>
{% else %}
<div class="row mt-5">
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_register/'">Register</button>
</div>
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_login/'">Login</button>
</div>
</div>
{% endif %}
{% endblock %}
{% if request.session.login_userkey %}
<div class="row mt-5">
<div class="col-12">
<h4>Login user key : {{ request.session.login_userkey }}</h4>
<h6>Login user name : {{ request.session.login_username }}</h6>
</div>
</div>
{% else %}
<div class="row mt-5">
<div class="col-12">
<h4>Not Logined</h4>
</div>
</div>
{% endif %}
마찬가지로 session을 이용할겁니다.
로그인할 때 session의 login_userkey에 로그인한 유저의 primary key를 저장해뒀었죠?
이 값을 불러오려면 request.session.login_userkey처럼 불러올 수 있습니다.
dictionary처럼 사용하면 됩니다.
또한 django에선 html 파일에서 {%%}라는 기호를 이용하여 if 문을 사용할 수 있습니다.
즉, 위 코드는 session의 login_userkey에 값이 있으면 seesion에 저장된 유저의 정보를 출력해주고,
그렇지 않으면 로그인을 하지 않았다는 뜻이니 Not Logined라는 메세지를 출력해주는 코드입니다.
{% if request.session.login_userkey %}
<div class="row mt-5">
<div class="col-12">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_logout/'">Logout</button>
</div>
</div>
{% else %}
<div class="row mt-5">
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_register/'">Register</button>
</div>
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="location.href='/user/user_login/'">Login</button>
</div>
</div>
{% endif %}
이 부분도 마찬가지입니다.
session의 login_userkey에 값이 있으면 로그인을 한 상태란 뜻이니 logout버튼을 출력해주고
그렇지 않다면 회원가입과 로그인버튼을 출력해주도록 하는 뜻입니다.
근데 아직 로그아웃 기능은 구현하지 않았죠.
로그아웃 기능도 구현해봅시다.
마찬가지로 MTV 순서를 따를텐데 Model은 이미 있고, 로그아웃은 따로 Template이 필요하지 않으니 바로 view코드로 넘어가면 되겠네요.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
# Create your views here.
def view_logout(request):
login_userkey = request.session.get('login_userkey', None)
login_username = request.session.get('login_username', None)
if login_userkey:
del request.session['login_userkey']
if login_username:
del request.session['login_username']
return redirect('/')
위처럼 로그아웃 기능을 구현했습니다.
로그아웃이란 session에 저장된 로그인 유저 정보를 다 삭제하는 것입니다.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
# Create your views here.
def view_logout(request):
login_userkey = request.session.get('login_userkey', None)
login_username = request.session.get('login_username', None)
...
먼저 위처럼 session에 저장된 로그인 정보를 불러옵니다.
마찬가지로 dictionary처럼 사용하면 됩니다. 따라서 get 함수를 썼죠.
우리는 login_userkey와 login_username을 저장했으니 이를 불러와서 이 두 값이 존재할 경우 del 을 이용해 session에서 key('login_userkey', 'login_username')에 대응하는 value를 제거하는 코드를 작성한 것입니다.
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password
from . import models as userapp_model
# Create your views here.
def view_logout(request):
...
if login_userkey:
del request.session['login_userkey']
if login_username:
del request.session['login_username']
...
if login_userkey:를 따로 체크하는 것은 혹시나 어떠한 에러로 인해 세션에 값이 저장되어있지 않은데 del method를 이용하는 경우 에러가 뜨게 됩니다.
따라서 session에 값이 있을 때에만 del 명령을 실행하도록 하기 위해 if 구문을 추가한 것입니다.
그리고 마지막으로 session에 있는 정보 삭제에 성공하면 home으로 redirect를 해주죠.
자 이제 logout도 어떤 url이 입력됐을 때 실행될지를 설정하기 위해 urls.py에서 url을 연결해줍시다.
from django.contrib import admin
from django.urls import path, include
from . import views as userapp_view
urlpatterns = [
path('user_register/', userapp_view.view_user_register),
path('user_login/', userapp_view.view_user_login),
path('user_logout/', userapp_view.view_logout)
]
여기까지하고 로그인을 다시 해보면 Home화면에 아래처럼 로그인 정보가 뜨며 로그아웃 버튼이 있는걸 알 수 있습니다.
로그아웃 버튼을 누르면
이렇게 로그인 전 화면으로 돌아가게되죠.
'Python django > Python django project 1' 카테고리의 다른 글
Python django project 1 - 게시판 만들기 ch.10 : 게시글 목록 만들기 (0) | 2020.12.20 |
---|---|
Python django project 1 - 게시판 만들기 ch.9 : static 파일(Bootstrap 디자인 변경) (0) | 2020.12.20 |
Python django project 1 - 게시판 만들기 ch.7 : 회원가입 (0) | 2020.12.13 |
Python django project 1 - 게시판 만들기 ch.6 : template & view (0) | 2020.12.13 |
Python django project 1 - 게시판 만들기 ch.5 : django admin (0) | 2020.12.13 |