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!
沒有留言:
張貼留言