Django
20210203_ Django 로그인,세션처리, render, redirect, is_valid, clean(), form 활용
Django
로그인
redirect 처리
확인해 보면 (개발자 툴 - Application - cookies)
브라우저가 다르면는 session을 다르게 인식하기 때문에 시크릿 모드 브라우저와 그냥 브라우저와 session id와 토큰이 다르다
각 세션 아이디 별로 세션 공간이 따로 존재하는데 이것을 쿠키임-> 자동으로 세션 관리해줌으로 그냥 쓰면 됨
세션 값들이 클라이언트를 식별하게 해주는 식별자가 됨
render vs redirect
render
:render(request, template_name, context=None, content_type=None, status=None, using=None)
- context 값을 넘길 수 있음, 템플릿을 불러옴
redirect
:redirect(to, permanent=False, *args, **kwargs)
- 단지, URL로 이동함(이동하여 해당 views가 다시 실행됨) context 값 못 넘김
세션과 로그인 처리
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth.hashers import make_password, check_password # 저장된 password 암호화
from .models import Fcuser
# Create your views here.
def login(request):
if request.method == 'GET':
return render(request, '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['error'] = '모든 값을 입력해 주세요.'
else:
sl_user = Sl_user.objects.get(username=username)
if check_password(password, sl_user.password):
user_id = sl_user.username
# 객체의 username을 user_id 할당
request.session['user'] = user_id
# 세션에서 user를 key로하고 값을 할당 받은 user_id로 설정
return redirect('/')
# '/' 홈으로 가게 만듦음
else:
res_data['error'] = '잘못된 아이디 또는 비밀번호 입니다.'
return render(request, 'login.html', res_data)
home 만들기
- home의 경우 어느 앱에도 속하지 않는 최상단 url로서 일단 프로젝트 폴더 urls를 설정한다. (결국에는 sl_user.views에서 home 함수를 만들어서 프로젝트 url로 연결)
- 프로젝트 urls.py
from django.contrib import admin
from django.urls import path, include
from sl_user.views import home
urlpatterns = [
path('admin/', admin.site.urls),
path('sl_user/', include('sl_user.urls')),
path('', home)
]
- views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password, check_password # 저장된 password 암호화
from .models import Sl_user
# Create your views here.
def home(request):
user_id = request.session.get('user')
# home의 세션을 user_id에 할당 시켜서
if user_id:
sl_user = Sl_user.objects.get(pk=user_id) # pk primary key
# 모델에서 키가 user_id인 경우의 객체를 가져와 sl_user에 할당
return HttpResponse(sl_user.username)
# sl_user 객체의 username을 반환하여 표시
return HttpResponse('Home!') # 맞지 않으면 Home!으로 표시
- 로그아웃
def logout(request):
if request.session.get('user'):
del(request.session['user'])
# 세션이 있으면 세션을 제거하여 로그아웃 됨
return redirect('/')
- 로그인, 로그아웃 url연결
from django.urls import path
from.import views
urlpatterns = [
path('register/', views.register),
path('login/', views.login),
path('logout/', views.logout),
]
template 상속
html 구성이 대부분이 중복되고 조금 다르기에 상속으로 효율적으로 할 필요가 있음
또한 수정시 유지 보수의 편의성을 위해서 필요함
기준 template를 만들고 상속받아 원하는 부분만 바꿈
base.html
을 만들어서 무조건 중복되는 부분을 만듦container
클래스 안에 부분이 변경 됨으로 그 부분만 바꾸도록 설정블록 구성이나 지정할때 주석 넣으면 인식 안됨 주의!
base.html
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> -->
<!-- bootstrap에서 다운받은 stylesheet 를 연결시켜 적용 -->
<link rel="stylesheet" href="/static/bootstrap.min.css" />
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
{% block contents %}
{% endblock %}
</div>
</body>
</html>
- login.html
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>로그인</h1>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
{{error}}
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<form method="POST", action=".">
{% csrf_token %}
<div class="form-group">
<label for="username" class="form-label">사용자 이름</label>
<input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username">
</div>
<div class="form-group">
<label for="password" class="form-label">비밀번호</label>
<input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
</div>
<button type="submit" class="btn btn-primary">로그인</button>
</form>
</div>
</div>
{% endblock %}
- register.html
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>회원가입</h1>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
{{error}}
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<form method="POST", action=".">
{% csrf_token %}
<div class="form-group">
<label for="username" class="form-label">사용자 이름</label>
<input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username">
</div>
<div class="form-group">
<label for="useremail" class="form-label">사용자 이메일</label>
<input type="email" class="form-control" id="useremail" placeholder="사용자 이메일" name="useremail">
</div>
<div class="form-group">
<label for="password" class="form-label">비밀번호</label>
<input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
</div>
<div class="form-group">
<label for="re-password" class="form-label">비밀번호 확인</label>
<input type="password" class="form-control" id="re-password" placeholder="비밀번호 확인" name="re-password">
</div>
<button type="submit" class="btn btn-primary">등록</button>
</form>
</div>
</div>
{% endblock %}
django form을 이용한 구성
django에서 제공하는 form 만들기 기능을 통해서 html, view를 좀더 쉽게 구현 가능함
form이 제공하는 기본적인 기능들이 있지만 그것에서 조건을 추가하여 전에 기능을 구현 가능함 (복잡해 보여도 조금더 단순하게 view 구성이 가능함)
form 구성
- models 만드는 느낌으로 구성함
- 폼을 구성하는 필드를 만듦
error_messages
속성은 views파일에서 form의 자체 함수is_valid()
error 통해 나타 나는 에러 메세지를 수정할 수 있음(기본 key가 required로 되어 있음)password
의widget
속성은 html에서 input에 대한 속성을 지정 가능label
은 위에 나타나는 label임
- clean vs is_vaild
- 원래
clean
은 기본 내장함수로 views의is_vaild
실행시 값의 존재 유무를 체크하여 타당한 값을 자동으로cleaned_data
라는 dict형태의 변수에 저장함 - 폼 안의
clean
함수를 지정하는 이유는 기본 내장함수를 오버라이딩 하여 viewsis_vaild
실행시 빈값만이 아닌 조건을 커스터 마이징 하기 위함임 - 그래서 기본적으로 빈값체크를 위해서
cleaned_data = super().clean()
인 부모의 clean 함수를 통해 미리 cleaned_data를 체크하고 우리가 필요한 조건을 검사하게 함
- 원래
username = cleaned_data.get('username')
,password = cleaned_data.get('password')
를 통해서 해당 필드의 값을 가져와 할당함
- form.py
from django import forms
from .models import Fcuser
from django.contrib.auth.hashers import check_password
class LoginForm(forms.Form):
username = forms.CharField(error_messages={
'required': '아이디를 입력해 주세요.'
}, max_length=32, label="사용자 이름")
password = forms.CharField(error_messages={
'required': '비밀번호를 입력해 주세요.'
}, widget=forms.PasswordInput, label="비밀번호")
def clean(self):
cleaned_data = super().clean()
username = cleaned_data.get('username')
password = cleaned_data.get('password')
if username and password:
sl_user = Sl_user.objects.get(username=username)
#Sl_user모델의 객체에서 가져온다(username 필드와 아까 할당한 username과 같은 객체) -> sl_user 변수에 할당
if not check_password(password, sl_user.password):
# check_password를 통해 입력 받은 password와 sl_user의 password와 비교
self.add_error('password', '비밀번호가 일치하지 않습니다.')
# form 안에 기본적으로 있는 add_error()함수로 특정 필드에 error를 넣는 함수임(password를 키로 하고 값을 지정)
else:
self.user_id = sl_user.id
# 이상 없으면 일치하는 객체 sl_user의 id를 use_id에 할당
views 구성
- POST를 받는 형식은 같지만
def login(request):
if request.method == "POST":
form = LoginForm(request.POST) # POST 데이터를 넣어서 form변수에 할당
if form.is_valid(): # is_valid() 함수를 통해 정상적인지 검증(값이 단지 들어가 있는지 확인하는데 전에 커스터마이징 했음)
# 세션 코드
request.session['user'] = form.user_id
return redirect('/')
else:
form = LoginForm() # 맞지 않으면 post 할당하지 않음
return render(request, 'login.html', {'form': form})
- html 데이터 표현 형식 설정
{{ form.as_p}}
: 각요소를 P태그를 붙여서 정렬됨{{form.as_table}}
: 각요소가 한줄로{% for field in form %}
,{% endfor %}
: form을 for 반복문으로 넣을 수 있음- 그리고 안에 어떤 형식을 반복할 것인지 넣을 수 있음
- django reference-Looping over the form’s fields
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12 text-center">
<h1>로그인</h1>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
{{error}}
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<form method="POST", action=".">
{% csrf_token %}
<!-- for반복문 넣기 -->
{% for field in form %}
<!-- 생성된 form의 fireld 가져와 반복 -->
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}" placeholder="{{ field.label }}" name="{{ field.name }}">
</div>
{% if field.errors %}
<!-- field 에러시 if 조건문 -->
<span style="color: red">{{ field.errors }}</span>
{% endif %}
{% endfor %}
<button type="submit" class="btn btn-primary">로그인</button>
</form>
</div>
</div>
{% endblock %}
'Django' 카테고리의 다른 글
20210206_Django 태그 기능, get_or_create, ManyToManyField, 배포(pythonanywhere) (0) | 2021.02.07 |
---|---|
20210205_Django 예외 처리, 기능보완, request.get, request.GET, 페이징(paginator, page) (0) | 2021.02.06 |
20210204_ Django 게시판 리스트 화면, 글쓰기 화면, 글 보기 화면 만들기, template language, form (0) | 2021.02.05 |
20210202_ Django admin, template,view만들기, url연결 - 회원가입, 로그인 (0) | 2021.02.03 |
20210129_ Django 가상환경 설정, MVC, MVT (0) | 2021.01.29 |