반원 블로그

django - 로그인 기능 수정(1) - forms.py 상속, 템플릿 for 본문

2018~/Django 개인 공부 정리

django - 로그인 기능 수정(1) - forms.py 상속, 템플릿 for

반원_SemiCircle 2019. 9. 8. 20:26

1. 목표

  • 현재 장고의 로그인을 html에 form 태그를 사용해서 만들었는데, 이를 django에서 제공하는 forms.py를 상속받아 구현해보자.

2.login.html 정리

  • 현재 login.html에서 로그인과 관련된 부분을 제거한다.
  • 나중에 views.py에서 def login코드도 깨끗하게 정리해야 하는데, 이는 일단 미뤄두자.
<!-- 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 %}
            <!-- 원래 로그인 form-group이 있었던 곳 -->
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
</div>
{% endblock %}

3. forms.py 생성

  • 앱 폴더(fuser)에 forms.py를 생성한다.

4.forms.py 정의

  • forms.py에 입력받을 값들에 대해서 Model를 만들어준다.
  • from django import forms
  • 각 값의 사이즈는 fuser.models.py에서 정의했던 사이즈와 같게 만들어주자.
  • Model을 클래스로 정의할 때 forms.Form을 상속받도록 한다.
  • split으로 models.py를 놓고 작업하면 편하다.(그냥 필요한 것만 복사해오자.)
  • 현재 username과 password란 2필드를 가진 model이 정의되었다.
#forms.py
from django import forms

class LoginForm(forms.Form):
    username = forms.CharField(max_length=32)
    password = forms.CharField()

5. 뷰 수정

  • views.py에서 다음처럼 코드를 고쳐, 방금 정의한 model를 화면에 보여주자

  • 방금 정의한 forms.py를 가져오기위해서 from .froms import LoginForm

  • def login 에서 LoginForm 인스턴스를 생성한다.

  • 생성한 LoginForm 인스턴스를 응답데이터에 넘겨준다. 이 때 데이터 키는 'form'으로 주었다.

  • 기존

    def login(request):
      if request.method=="GET":
          return render(request,'login.html')
      elif request.method == "POST" :
          #전송받은 이메일 비밀번호 확인
          username = request.POST.get('username')
          password = request.POST.get('password')
    
          #유효성 처리
          res_data ={}
          if not (username and password):
              res_data['error']="모든 칸을 다 입력해주세요"
          else:
              # 기존(DB)에 있는 Fuser 모델과 같은 값인 걸 가져온다.
              fuser = Fuser.objects.get(username = username) #(필드명 = 값)
    
              # 비밀번호가 맞는지 확인한다. 위에 check_password를 참조
              if check_password(password, fuser.password):
                  #응답 데이터 세션에 fuser의 기본키(pk)값인 id 추가. 나중에 쿠키에 저장됨
                  request.session['user']=fuser.id
    
                  #리다이렉트
                  return redirect('/')
              else:
                  res_data['error'] = "비밀번호가 틀렸습니다."
    
          return render(request,'login.html',res_data) #응답 데이터 res_data 전달
  • 변경

    def login(request):
      form = LoginForm()
      return render(request,'login.html',{'form':form}) #응답 데이터 res_data 전달

6. login.html에 전송한 form 1차 표현

  • login.html에서 응답받은 데이터를 표현할 수 있도록 한다.
  • 템플릿 표현식인 {{ form }}을 사용하자.
<!-- 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 %}
            <!-- 원래 로그인 form-group이 있었던 곳 -->
            {{ form }}
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
</div>
{% endblock %}

7. 결과

  • 값을 입력하지 않으면 알아서 값을 입력해야된다고 나온다.
  • 비밀번호가 그대로 노출된다.

8.웹 페이지에서는 응답데이터 활용

  • 응답받은 form 모델을 다양한 형태로 출력할 수 있다.
  • 예 : {{form.as_p}} - 각 필드 하나하나를 p 태그로 감싼다.
  • 예 : {{form.as_table}} - 각 필드를 테이블로 자동 생성해준다.
  • 그러나 이렇게 제공하는 기능들로 원하는 페이지를 만들기는 부족하다.

9.템플릿 표현식 for 사용하기

  • 받은 응답데이터를 for문을 이용하여 원하는 형태로 표현해보자.

  • 템플릿 for 표현식은 다음과 같다.(파이썬 for와 유사하다)

    {% for 변수명 in 연결형데이터 %}
    반복코드
    {% endfor %}
  • 먼저 실질적으로 field를 적용하기전 디자인만 추가

10.field를 적용

  • 응답데이터의 field를 적용해보자.
  • forms.py에서 정의하여 만든 LoginForm에서의 필드들은 여러 속성(변수)들을 가지고 있다.
  • .id_for_label : id 입력을 위한 레이블
  • .label : 단순 표현을 위한 레이블
  • .field.widget.input_type : 해당 필드가 웹 페이지에서 입력받아야 할 input태그의 타입
  • .field.name : 해당 field의 name
<div class="row mt-5">
    <div class="col-12">
        <form method="POST" action=".">
            {% csrf_token %}
            <!-- 원래 로그인 form-group이 있었던 곳 -->
            {% 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>
            {% endfor %}
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
</div>

11 원하는 label과 input_type 지정

  • forms.py에서 정의했던 field를 재정의 해보자.
  • forms.PasswordInput 에는 비밀번호 입력을 위한 widget이 있으며 여기 내부에 textarea 등의 여러 태그들이 미리 정의되있다.
#forms.py
from django import forms

class LoginForm(forms.Form):
    username = forms.CharField(max_length=32, label="아이디")
    password = forms.CharField(label="비밀번호", widget=forms.PasswordInput )

아직 처리되지 않은 것

  • id와 비밀번호 매칭 후 로그인 처리
Comments