Django 로 게시판 만들기(15). 장고 Form 2

.·2020년 7월 27일
1

게시판만들기

목록 보기
15/21

1. def login(request):

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})

2. is_vaild() 의 에러 정보 출력하기

로그인 페이지에서 아이디, 비밀번호 둘 다 아무 값이나 입력하고 로그인해 보면, '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 가 출력이 된다.

지금 진행한 유효성 검사는 값이 들어 있는지 아닌지에 대한 것이다.

이제 비밀번호가 일치하는지 일치하지 않는지에 대한 검증이 필요하다.

3. clean()

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 안에 들어 있던 클린함수를 먼저 호출해준다. 라고 했다.

4. username 과 password 가 있을 때

# 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 를 넣는 함수이다.
테스트를 해보면 아래 화면과 같이 에러 메시지를 출력한다.

5. field 에 값을 입력하지 않았을 때 메시지 변경하기

"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="비밀번호")

6. login session 코드를 view 에 넣기

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})

7. forms.py 전체 코드

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


profile
.

1개의 댓글

comment-user-thumbnail
2021년 7월 10일

쉽게 찾을 수 있는 오류이지만 login 함수에서 if request == "POST" 부분이 if request.method == "POST"으로 수정되어야 할 것 같습니다. 작성하신 글로부터 많이 배우고 있습니다. 감사합니다. :)

답글 달기