form 을 이용하므로 views.py 내 작성한 로그인 함수는 전보다 코드가 간결해질 예정이다.
저번과 마찬가지로 로그인함수는 http method 가 POST 인지 GET 인지에 따라 나뉘어 진다.
def login(request):
if request == "POST":
form = LoginForm(request.POST)
# 폼 객체, 폼 클래스를 만들 때 괄호에 POST 데이터를 담아준다.
# POST 안에 있는 데이터가 form 변수에 들어간다.
if form.is_valid(): # 장고 폼에서 제공하는 검증 함수 is_valid()
# session_code 검증
return redirect('/')
else:
form = LoginForm()
# 빈 클래스 변수를 만든다.
return render(request, 'login.html', {'form':form})
로그인 페이지에서 아이디, 비밀번호 둘 다 아무 값이나 입력하고 로그인해 보면, 'Home!' 으로 리다이렉트 된다. 정상적으로 입력이 된 것으로 인식한다.
로그인 페이지에서 아이디, 비밀번호 둘 중 하나만 입력하고 버튼을 눌러보자. 그냥 form 로그인 페이지가 나왔다. 정상적으로 입력이 되지 않은 상태이지만, 여기서 아이디를 입력하세요, 비밀번호를 입력하세요 등의 에러 메시지를 띄워줄 필요가 있다.
form.is_vaild() 에는 에러 정보도 들어 있기에 이 에러를 출력하는 코드를 작성해 보자.
{% if field.errors %}
<span style="color: red;">{{ field.errors }}</span>
{% endif %}
login.html 에서 반복문 코드의 아래에 위와 같이 작성하였다.
테스트를 통해 필드 입력이 되지 않았을 때, "This field is required" 라는 메시지를 확인할 수 있다.
{% for field in form %}
<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 %}
<span style="color: red;">{{ field.errors }}</span>
{% endif %}
{% endfor %}
실제로 에러가 나면 is_valid() 에서 유효성 검사를 하고 유효하지 않으면 그 form 안에 에러 정보가 들어있게 되고 그게 form 으로 전달이 되며 html 파일의 field.errors 를 통해 화면에 error message 가 출력이 된다.
지금 진행한 유효성 검사는 값이 들어 있는지 아닌지에 대한 것이다.
이제 비밀번호가 일치하는지 일치하지 않는지에 대한 검증이 필요하다.
forms.py 에 있는 LoginForm 클래스 안에 클린 함수를 작성한다.
class LoginForm(forms.Form):
# 입력받을 값 두개
username = "생략"
password = "생략"
def clean(self):
cleaned_data = super().clean()
# 처음 값이 들어왔다 는 검증 진행
username = cleaned_data.get('username')
password = cleaned_data.get('password')
클린 함수가 뭐지?
나와 같은 공부를 진행하는 블로그에서 따왔다.
def clean(self): 메소드를 정의한다.(오버라이드). 이는 이미 정의되있는 메소드인데, 이게 이미 수행되고 있는 값이 비어있는지(clean) 검사하는 메소드이다.
오버라이드 하므로 super().clean() 메소드를 호출한다.(값 비어있는지 확인)
super().clean() 메소드 호출한 뒤, 각 값을 통해 등록된 회원인지 검사하도록 한다.
강의에서는 이미 기본적으로 만들어져 있기 때문에 super() 를 통해서 기존에 Form 안에 들어 있던 클린함수를 먼저 호출해준다. 라고 했다.
# cleaned_data 의 첫 검증이 끝난 데이터 에서 이제 값이 들어있나 확인하기
if username and password:
member = BoardMember.objects.get(username=username)
# 세션처리는 views 내 login 함수에서! 검증만 한다.
# 위에 (forms.py) from django.contrib.auth.hashers import check_password 입력
if not check_password(password, member.password):
# check_password 의 앞 password 는 입력받은 값, 뒤는 모델안에 저장되어 있는 값
self.add_error('password', '비밀번호가 다릅니다!')
폼 안에 기본적으로 add_error() 라는 함수가 있는데, 이 함수는 특정 필드에다가 error 를 넣는 함수이다.
테스트를 해보면 아래 화면과 같이 에러 메시지를 출력한다.
"This field is required" 제공하는 기본 문구를 입맛에 맞게 바꿔보자.
위의 기본 문구는 'required' 라는 키에 들어 있다.
LoginForm 의 CharField 안에 아래와 같이 코드를 입력한다.
error_messages = {
'required': '아이디를 입력해 주세요'
}
비밀번호도 마찬가지로 동일한 방법으로 입력해보고 테스트 해보자.
class LoginForm(forms.Form):
# 입력받을 값 두개
username = forms.CharField(error_messages={
'required':'아이디를 입력하세요!'
},max_length=100, label="사용자이름")
password = forms.CharField(error_messages={
'required':'비밀번호를 입력하세요!'
},widget=forms.PasswordInput, max_length=100, label="비밀번호")
if form.is_valid():
request.session['user'] = ""
세션의 user 라는 키에 id 값을 넣어야 하는데 없으므로 forms.py 에서 코드 입력을 통해 가져와 보자.
다시 forms.py 로 돌아가서, check_password 가 맞았을 때 코드를 작성해 본다. (else)
else:
self.user_id = member.id
이렇게 하면 self 를 통해서 class 변수 안에 들어가게 된다. 그러면 외부에서(views에서도) 접근할 수가 있게 된다.
이제 다시 view 로 돌아가 마저 작성해 보면,
if form.is_valid():
request.session['user'] = form.user_id
return redirect('/')
is_valid() 에 의해 이미 검증이 된 상태이기 때문에, 검증에 대한 조건을 걸어 놓았기 때문에 이렇게 접근했을 때 'user_id' 라는 변수는 무조건 존재하게 된다.
장고에서 제공하는 form 객체로 로그인을 만들었고 로그인 시 로그인한 아이디가 나오는 것을 확인해 볼 수 있다.
def login(request):
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
# session_code 검증하기
request.session['user'] = form.user_id
return redirect('/')
else:
form = LoginForm()
return render(request, 'login.html', {'form': form})
from django.contrib.auth.hashers import check_password
from django import forms
from .models import BoardMember
class LoginForm(forms.Form):
# 입력받을 값 두개
username = forms.CharField(error_messages={
'required':'아이디를 입력하세요!'
},max_length=100, label="사용자이름")
password = forms.CharField(error_messages={
'required':'비밀번호를 입력하세요!'
},widget=forms.PasswordInput, max_length=100, label="비밀번호")
# 처음 값이 들어왔다 는 검증 진행
def clean(self):
cleaned_data = super().clean()
username = cleaned_data.get('username')
password = cleaned_data.get('password')
if username and password:
member = BoardMember.objects.get(username=username)
if not check_password(password, member.password):
self.add_error('password', '비밀번호가 다릅니다!')
else:
self.user_id = member.id
쉽게 찾을 수 있는 오류이지만 login 함수에서 if request == "POST" 부분이 if request.method == "POST"으로 수정되어야 할 것 같습니다. 작성하신 글로부터 많이 배우고 있습니다. 감사합니다. :)