데이터 검증 - 폼 모듈

Red_Panda·2021년 3월 22일
0

form은 사용자에게 입력 양식을 편리하게 제공하기 위해 사용한다. flask의 form 모듈을 사용하면 form으로 전송되는 데이터들을 여러가지 조건으로 쉽게 검증할 수 있다.

플라스크 폼 모듈 설치

cmd -> myproject에서

pip install Flask-WTF

로 라이브러리를 설치한다.

Flask-WTF를 사용하려면 플라스크 환경변수 SECRET_KEY가 필요한데, 이것은 CSRF(cross-site request forgery)라는 웹사이트 취약점 공격 방지에 사용한다.
CSRF는 사용자 요청을 위조해 웹사이트를 공격하는 방식인데 이러한 공격을 방지 하기 위해 SECPET_KEY를 기반으로 CSRF 토큰을 생성한다. 이 토큰은 폼으로 전송된 데이터가 실제로 웹 페이지에서 작성된건지 판단할때 도움을 준다.

설치가 끝나면 config.py 파일 마지막 줄에

SECRET_KEY = "dev" 

를 입력해 환경변수를 추가한다. 개발환경일때는 간단한 문자열을 넣어도 상관없다. dev말고 다른 문자열을 넣어도된다.

질문 등록 기능

먼저 질문 목록 리스트 화면(question_list.html)에서 질문 등록 버튼을 만들어준다.

버튼의 다른 색상 및 옵션은 아래 부트스트랩 사이트에서 알 수 있다.
https://getbootstrap.com/docs/4.1/components/buttons/

다음으로, question_views.py에 질문 등록 라우트 함수를 추가해준다.

QuestionForm 클래스는 질문 등록때 사용할 플라스크 폼이다. QuestionForm 클래스의 객체 form 을 생성 후 render_template 함수로 렌더링해 form 객체를 전달한다.
그리고 from ..forms import QuestionForm 를 맨위에 넣어 import 해준다.

다음 순서로 위에서 언급한 QuestionForm 클래스를 만든다.
pybo 디렉토리에 forms.py 파일을 만들어 다음과 같이 작성한다.

Flask-WTF 모듈의 FlaskForm 클래스를 상속 받는다. StringField는 글자수 제한이 있고, TextAreaField는 글자수 제한이 없다.

StringField의 첫번째 인자는 폼 라벨로 사용, 두번째 인자 validators는 필드값을 필수항목인지, 메일인지 등등 조건에 맞게 검증할때 사용 한다.

이제 질문 등록 폼을 보여줄 템플릿을 만든다. question 디렉토리에 question_form.html을 생성하고 다음과 같이 작성한다.


질문 등록하기를 누르면 등록 페이지는 뜬다. 다만 저장을 누르면 오류메시지가 뜬다.
create 라우트에는 별도의 메서드 속성을 지정하지않아 디폴트값인 GET 방식만 처리할 수 있다. 그래서 POST방식도 처리할 수 있도록 질문 등록 라우트를 변경한다.

@bp.route('/create/') >>
@bp.route('/create/', methods=('GET', 'POST'))

그리고 qestion_views.py 파일에 폼 데이터를 저장하는 코드를 추가한다.

<추가내용>

from datetime import datetime

from flask import Blueprint, render_template, request, url_for
from werkzeug.utils import redirect
from .. import db

@bp.route('/create/',methods=('GET','POST'))
def create():
    form = QuestionForm()
    if request.method == 'POST' and form.validate_on_submit():
        question = Question(subject=form.subject.data, content=form.content.data, create_date=datetime.now())
        db.session.add(question)
        db.session.commit()
        return redirect(url_for('main.index'))
    return render_template('question/question_form.html', form=form)

if request.method == 'POST' and form.validate_on_submit()

create함수로 요청된 전송방식이 POST 면서 전송된 폼 데이터의 정합성을 점검해 문제 없으면 질문을 생성해 저장한다.

나머지는 answer.views.py의 create와 유사하다.

질문 등록하기와 저장하기 버튼은 같은 페이지(localhost:5000/question/create/ )를 요청하기 때문에, 요청 방식에따라 구분한다. 질문 등록하기는 GET, 저장하기는 POST 방식이다.

{{ form.subject() }}와 같은 코드는 폼을 생성하는 HTML 코드를 자동으로 만들어 줬다. 하지만, 원하는 디자인을 적용 및 엘리먼트나 속성을 추가하기 어렵다.

그래서 form 화면을 HTML로 직접 작성해 만들어본다. HTML로 작성하니 딱 붙어있었던 저장하기 버튼이 보기좋게 간격이 생겼다.

만약 디자인요소에 신경쓰기 싫다면 HTML코드를 자동으로 생성하는 방식을 사용해도 될듯하나, 역시 HTML코드로 보기좋게 하는게 좋겠다.

근데 저장하기 버튼을 눌러도 아무 반응이 없다. 어떤 오류인지 알기위해 템플릿을 수정해 오류 내용을 표시 해보자.

question_form.html 안에 위와같은 코드를 추가해준다.
form.errors.items() 의 filed는 subject, content 등 입력 폼의 필드
form.validate_on_submit이 false일때 위에 추가한 코드 위치에 오류가 표시된다.

제목, 내용을 입력하고 저장했더니 위와 같은 영어로 오류가 뜨면서 저장에 실패한다. 근데 입력한 내용도 같이 사라진다..

CSRF 토큰 오류를 처리 하는 방법은 question_form.html 에서

<form method="post" class="post-form my-3">

코드 밑에 {{ form.csrf_token }} 코드를 추가해주면 된다.

또, 오류 발생시 작성했던 내용이 사라지지 않게 하려면 question_form.html 파일의 코드를 아래와 같이 수정한다.

<input type="text" class="form-control" name="subject" id="subject" value="{{ form.subject.data or '' }}">

<textarea class="form-control" name="content" id="content" rows="10">{{ form.content.data or '' }}</textarea>
로 수정해준다.

value="{{ form.subject.data or '' }}" : 입력 값이 있으면 입력한 값, 없으면 ''(공백) 출력.

오류 발생시, 영어 오류문구가 뜨는데 이를 수정하려면 DataRequired() 코드 괄호안에 '원하는 문구'를 넣어주면 된다.

subject = StringField('제목', validators=[DataRequired('반드시 제목을 입력해주세요')])
    content = TextAreaField('내용', validators=[DataRequired('반드시 내용을 입력해주세요')])


와 이제 질문글이 등록된다.


지금은 위와 같이 빈칸으로 입력해도 답변 작성이 되었는데, 질문 글 작성처럼 답변 내용을 반드시 입력해야 등록되게 form을 만들어 답변 기능도 수정하자.
<forms.py>

<answer_views.py>

<question_detail.html>

<question_views.py>

질문 form을 만드는 과정과 똑같다.

profile
신입 개발자

0개의 댓글