폼 검증 (WTForms) — 폼을 클래스로 정의하고 검증하기
폼 검증 (WTForms) — 폼을 클래스로 정의하고 검증하기
브라우저 뷰가 제출한 폼 데이터를 다루다 보면 코드가 금방 읽기 어려워져요. 이 과정을 더 쉽게 관리하도록 설계된 라이브러리가 있는데, 그중 하나가 WTForms예요. 폼이 많아지는 상황이라면 한번 써 보는 걸 추천해요.
WTForms를 쓸 때는 먼저 폼을 클래스로 정의해야 해요. 앱을 여러 모듈로 나누고 폼용 별도 모듈을 추가하는 걸 권장해요.
본문
확장으로 WTForms를 최대한 활용하기
Flask-WTF 확장은 이 패턴을 확장하고 폼과 Flask를 다루는 걸 더 즐겁게 해주는 몇 가지 작은 헬퍼를 추가해요. PyPI 에서 받을 수 있어요.
폼 정의
전형적인 등록 페이지용 예시 폼이에요.
from wtforms import Form, BooleanField, StringField, PasswordField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
뷰에서 사용
뷰 함수에서 이 폼의 사용법은 이렇게 생겼어요.
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
user = User(form.username.data, form.email.data,
form.password.data)
db_session.add(user)
flash('Thanks for registering')
return redirect(url_for('login'))
return render_template('register.html', form=form)
여기서 뷰가 SQLAlchemy를 쓴다고 암시하고 있지만, 그건 필수 조건이 아니에요. 필요에 따라 코드를 적응시키세요.
기억할 점들:
- 데이터가 HTTP
POST메서드로 제출되면 request의:attr:~flask.request.form값에서,GET으로 제출되면:attr:~flask.request.args에서 폼을 만들어요. - 데이터를 검증하려면
:func:~wtforms.form.Form.validate메서드를 호출해요. 데이터가 검증되면True, 그렇지 않으면False를 반환해요. - 폼에서 개별 값을 가져오려면
form.<NAME>.data에 접근해요.
템플릿에서 폼 렌더링
이제 템플릿 쪽이에요. 폼을 템플릿에 전달하면 거기서 쉽게 렌더링할 수 있어요. 다음 예시 템플릿을 보면 얼마나 쉬운지 알 수 있어요. WTForms가 폼 생성의 절반은 이미 해 주거든요. 더 깔끔하게 만들려면, 라벨과 오류 목록(있으면)을 가진 필드를 렌더링하는 매크로를 작성할 수 있어요.
:file:_formhelpers.html 템플릿에서 그런 매크로의 예시를 볼게요.
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
이 매크로는 WTForms의 field 함수에 전달되는 몇 가지 키워드 인자를 받아요. field 함수는 우리를
위해 필드를 렌더링해 주죠. 키워드 인자들은 HTML 속성으로 삽입돼요. 예를 들어
render_field(form.username, class='username')을 호출하면 input 요소에 class를 추가할 수 있어요.
WTForms는 표준 파이썬 문자열을 반환하므로, 이 데이터가 이미 HTML 이스케이프됐다는 걸 |safe
필터로 Jinja에 알려줘야 한다는 점을 기억하세요.
:file:register.html 템플릿은 위에서 쓴 함수용으로, :file:_formhelpers.html 템플릿을
활용해요.
{% from "_formhelpers.html" import render_field %}
<form method=post>
<dl>
{{ render_field(form.username) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm) }}
{{ render_field(form.accept_tos) }}
</dl>
<p><input type=submit value=Register>
</form>
WTForms에 대한 더 많은 정보는 WTForms 웹사이트를 봐요.
더 알아보기
- 템플릿 (Jinja) — 템플릿에서 폼 필드를 렌더링하는 배경
- Flask 퀵스타트 — request.form으로 요청 데이터 접근하기
- 블루프린트 — 폼이 담긴 뷰를 블루프린트로 나누기