User 要傳資料到 server 不外乎就是透過 HTML 表單搭配 HTTP method GET/POST,為了避免 user 輸入奇怪的資料造成 server 異常,通常我們都會去限定各欄位值域、資料形態、格式...這些東西,如果自己用一堆 if 去寫一定會寫到瘋掉,好在網路上已經有現成的 library 可以用。
表單驗證有可以分別在 client 端或跟 server 端去做:
- Client 端驗證
好處是可以減少 server loading,少了傳輸的 latency,反應速度也比較快,但這只能防君子不能防小人,client 端驗證是用 javascript,有心人只要把 script 修改一下就可以避過。
Library 可以參考:10 Useful jQuery Form Validation Techniques and Tutorials
- Server 端驗證
無論 client 端有沒有做,server 端做檢查是必然的事情啦!這也是我今天想介紹的,在 python 上我只用過一套:WTForms,一用就上癮,不只可以做到驗證,表單也可以自動產生。
如果你 web framework 是用 flask,已經有現成的 extension: Flask-WTF 可以用,我自己是用 tornado,必須要另外疊一個 wrapper,幸好已經有人幫忙寫好了: flying with tornado on appengine
下面以"個人資料更新"為例:
- custom_form.py - 定義自己的表單
class ProfileUpdateForm(form_wrapper.Form):
email = forms.StringField('email', [validators.Email()])
nickname = forms.StringField('nickname', [validators.Length(min=5, max=20)])
sex = forms.RadioField('sex', [validators.Required()], choices=[("0", "male"), ("1", "female")], default=0)
birthday = forms.DateField ('birthday')
country = forms.SelectField('country', choices=[("0", "TW"), ("1", "CN"), ("2", "US")])
height = forms.FloatField ('height', [validators.NumberRange(min=90.0, max=200.0)])
photo = forms.FileField('photo')
- general_form.html - 自動產生表單的 template
<form action="{{ request.uri }}" method="post" accept-charset="utf-8" enctype="multipart/form-data">
{% autoescape None %}
<table border="0">
{% for field in form %}
<tr>
{% import wtforms as forms %}
{% if type(field) == forms.RadioField %}
<td align="right">{{ field.label }}</td>
<td>
{% for subfield in field %}
{{ subfield }}{{ subfield.label }}
{% end for %}
{% elif type(field) == forms.SelectField %}
<td align="right">{{ field.label }}</td>
<td>
<select name="{{ field.id }}">
{% for subfield in field %}
{{ subfield }}
{% end for %}
</select>
{% else %}
<td align="right">{{ field.label }}</td><td>{{ field }}</td>
{% end if %}
</tr>
{% end %}
</table>
<input type="submit" value="Submit"/>
</form>
- profile.py - GET request handler
class ProfileUpdateHandler(tornado.web.RequestHandler):
def get(self):
form = ProfileUpdateForm()
self.render("general_form.html", form=form)
自動產生的表單如下:- profile.py - POST request handler
class ProfileUpdateHandler(tornado.web.RequestHandler):
def post(self):
form = ProfileUpdateForm(self)
if not form.validate():
return self.write("form validation fail: %s", form.errors)
在 form.errors 裡面會詳細說明哪個欄位出錯 good!

沒有留言:
張貼留言