Flask wtforms
生活随笔
收集整理的這篇文章主要介紹了
Flask wtforms
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
wtforms
簡(jiǎn)介
WTForms是一個(gè)支持多個(gè)web框架的form組件,主要用于對(duì)用戶請(qǐng)求數(shù)據(jù)進(jìn)行驗(yàn)證。
安裝:
?| 1 | pip3 install wtforms |
用戶登錄注冊(cè)示例
1. 用戶登錄
當(dāng)用戶登錄時(shí)候,需要對(duì)用戶提交的用戶名和密碼進(jìn)行多種格式校驗(yàn)。如:
用戶不能為空;用戶長(zhǎng)度必須大于6;密碼不能為空;密碼長(zhǎng)度必須大于12;密碼必須包含 字母、數(shù)字、特殊字符等(自定義正則);
2. 用戶注冊(cè)
注冊(cè)頁(yè)面需要讓用戶輸入:用戶名、密碼、密碼重復(fù)、性別、愛好等。
from flask import Flask, render_template, request, redirect from wtforms import Form from wtforms.fields import core from wtforms.fields import html5 from wtforms.fields import simple from wtforms import validators from wtforms import widgetsapp = Flask(__name__, template_folder='templates') app.debug = Trueclass RegisterForm(Form):name = simple.StringField(label='用戶名',validators=[validators.DataRequired()],widget=widgets.TextInput(),render_kw={'class': 'form-control'},default='alex')pwd = simple.PasswordField(label='密碼',validators=[validators.DataRequired(message='密碼不能為空.')],widget=widgets.PasswordInput(),render_kw={'class': 'form-control'})pwd_confirm = simple.PasswordField(label='重復(fù)密碼',validators=[validators.DataRequired(message='重復(fù)密碼不能為空.'),validators.EqualTo('pwd', message="兩次密碼輸入不一致")],widget=widgets.PasswordInput(),render_kw={'class': 'form-control'})email = html5.EmailField(label='郵箱',validators=[validators.DataRequired(message='郵箱不能為空.'),validators.Email(message='郵箱格式錯(cuò)誤')],widget=widgets.TextInput(input_type='email'),render_kw={'class': 'form-control'})gender = core.RadioField(label='性別',choices=((1, '男'),(2, '女'),),coerce=int)city = core.SelectField(label='城市',choices=(('bj', '北京'),('sh', '上海'),))hobby = core.SelectMultipleField(label='愛好',choices=((1, '籃球'),(2, '足球'),),coerce=int)favor = core.SelectMultipleField(label='喜好',choices=((1, '籃球'),(2, '足球'),),widget=widgets.ListWidget(prefix_label=False),option_widget=widgets.CheckboxInput(),coerce=int,default=[1, 2])def __init__(self, *args, **kwargs):super(RegisterForm, self).__init__(*args, **kwargs)self.favor.choices = ((1, '籃球'), (2, '足球'), (3, '羽毛球'))def validate_pwd_confirm(self, field):"""自定義pwd_confirm字段規(guī)則,例:與pwd字段是否一致:param field: :return: """# 最開始初始化時(shí),self.data中已經(jīng)有所有的值if field.data != self.data['pwd']:# raise validators.ValidationError("密碼不一致") # 繼續(xù)后續(xù)驗(yàn)證raise validators.StopValidation("密碼不一致") # 不再繼續(xù)后續(xù)驗(yàn)證 @app.route('/register', methods=['GET', 'POST']) def register():if request.method == 'GET':form = RegisterForm(data={'gender': 1})return render_template('register.html', form=form)else:form = RegisterForm(formdata=request.form)if form.validate():print('用戶提交數(shù)據(jù)通過(guò)格式驗(yàn)證,提交的值為:', form.data)else:print(form.errors)return render_template('register.html', form=form)if __name__ == '__main__':app.run() app.py <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h1>用戶注冊(cè)</h1> <form method="post" novalidate style="padding:0 50px">{% for item in form %}<p>{{item.label}}: {{item}} {{item.errors[0] }}</p>{% endfor %}<input type="submit" value="提交"> </form> </body> </html> register.html3. meta
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, render_template, request, redirect, session from wtforms import Form from wtforms.csrf.core import CSRF from wtforms.fields import core from wtforms.fields import html5 from wtforms.fields import simple from wtforms import validators from wtforms import widgets from hashlib import md5app = Flask(__name__, template_folder='templates') app.debug = Trueclass MyCSRF(CSRF):"""Generate a CSRF token based on the user's IP. I am probably not verysecure, so don't use me."""def setup_form(self, form):self.csrf_context = form.meta.csrf_context()self.csrf_secret = form.meta.csrf_secretreturn super(MyCSRF, self).setup_form(form)def generate_csrf_token(self, csrf_token):gid = self.csrf_secret + self.csrf_contexttoken = md5(gid.encode('utf-8')).hexdigest()return tokendef validate_csrf_token(self, form, field):print(field.data, field.current_token)if field.data != field.current_token:raise ValueError('Invalid CSRF')class TestForm(Form):name = html5.EmailField(label='用戶名')pwd = simple.StringField(label='密碼')class Meta:# -- CSRF# 是否自動(dòng)生成CSRF標(biāo)簽csrf = True# 生成CSRF標(biāo)簽namecsrf_field_name = 'csrf_token'# 自動(dòng)生成標(biāo)簽的值,加密用的csrf_secretcsrf_secret = 'xxxxxx'# 自動(dòng)生成標(biāo)簽的值,加密用的csrf_contextcsrf_context = lambda x: request.url# 生成和比較csrf標(biāo)簽csrf_class = MyCSRF# -- i18n# 是否支持本地化# locales = Falselocales = ('zh', 'en')# 是否對(duì)本地化進(jìn)行緩存cache_translations = True# 保存本地化緩存信息的字段translations_cache = {}@app.route('/index/', methods=['GET', 'POST']) def index():if request.method == 'GET':form = TestForm()else:form = TestForm(formdata=request.form)if form.validate():print(form)return render_template('index.html', form=form)if __name__ == '__main__':app.run() View Code其他:
1. metaclass
class MyType(type):def __init__(self, *args, **kwargs):print('MyType創(chuàng)建類',self)super(MyType, self).__init__(*args, **kwargs)def __call__(self, *args, **kwargs):obj = super(MyType, self).__call__(*args, **kwargs)print('類創(chuàng)建對(duì)象', self, obj)return objclass Foo(object,metaclass=MyType):user = 'wupeiqi'age = 18obj = Foo() 示例一 class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v = dir(cls)obj = super(MyType, cls).__call__(*args, **kwargs)return objclass Foo(MyType('MyType', (object,), {})):user = 'wupeiqi'age = 18obj = Foo() 示例二 class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v = dir(cls)obj = super(MyType, cls).__call__(*args, **kwargs)return objdef with_metaclass(arg,base):return MyType('MyType', (base,), {})class Foo(with_metaclass(MyType,object)):user = 'wupeiqi'age = 18obj = Foo() 示例三2. 實(shí)例化流程分析
# 源碼流程1. 執(zhí)行type的 __call__ 方法,讀取字段到靜態(tài)字段 cls._unbound_fields 中; meta類讀取到cls._wtforms_meta中2. 執(zhí)行構(gòu)造方法a. 循環(huán)cls._unbound_fields中的字段,并執(zhí)行字段的bind方法,然后將返回值添加到 self._fields[name] 中。即:_fields = {name: wtforms.fields.core.StringField(),}PS:由于字段中的__new__方法,實(shí)例化時(shí):name = simple.StringField(label='用戶名'),創(chuàng)建的是UnboundField(cls, *args, **kwargs),當(dāng)執(zhí)行完bind之后,才變成執(zhí)行 wtforms.fields.core.StringField()b. 循環(huán)_fields,為對(duì)象設(shè)置屬性for name, field in iteritems(self._fields):# Set all the fields to attributes so that they obscure the class# attributes with the same names. setattr(self, name, field)c. 執(zhí)行process,為字段設(shè)置默認(rèn)值:self.process(formdata, obj, data=data, **kwargs)優(yōu)先級(jí):obj,data,formdata;再循環(huán)執(zhí)行每個(gè)字段的process方法,為每個(gè)字段設(shè)置值:for name, field, in iteritems(self._fields):if obj is not None and hasattr(obj, name):field.process(formdata, getattr(obj, name))elif name in kwargs:field.process(formdata, kwargs[name])else:field.process(formdata)執(zhí)行每個(gè)字段的process方法,為字段的data和字段的raw_data賦值def process(self, formdata, data=unset_value):self.process_errors = []if data is unset_value:try:data = self.default()except TypeError:data = self.defaultself.object_data = datatry:self.process_data(data)except ValueError as e:self.process_errors.append(e.args[0])if formdata:try:if self.name in formdata:self.raw_data = formdata.getlist(self.name)else:self.raw_data = []self.process_formdata(self.raw_data)except ValueError as e:self.process_errors.append(e.args[0])try:for filter in self.filters:self.data = filter(self.data)except ValueError as e:self.process_errors.append(e.args[0])d. 頁(yè)面上執(zhí)行print(form.name) 時(shí),打印標(biāo)簽因?yàn)閳?zhí)行了:字段的 __str__ 方法字符的 __call__ 方法self.meta.render_field(self, kwargs)def render_field(self, field, render_kw):other_kw = getattr(field, 'render_kw', None)if other_kw is not None:render_kw = dict(other_kw, **render_kw)return field.widget(field, **render_kw)執(zhí)行字段的插件對(duì)象的 __call__ 方法,返回標(biāo)簽字符串 View Code3. 驗(yàn)證流程分析
a. 執(zhí)行form的validate方法,獲取鉤子方法def validate(self):extra = {}for name in self._fields:inline = getattr(self.__class__, 'validate_%s' % name, None)if inline is not None:extra[name] = [inline]return super(Form, self).validate(extra)b. 循環(huán)每一個(gè)字段,執(zhí)行字段的 validate 方法進(jìn)行校驗(yàn)(參數(shù)傳遞了鉤子函數(shù))def validate(self, extra_validators=None):self._errors = Nonesuccess = Truefor name, field in iteritems(self._fields):if extra_validators is not None and name in extra_validators:extra = extra_validators[name]else:extra = tuple()if not field.validate(self, extra):success = Falsereturn successc. 每個(gè)字段進(jìn)行驗(yàn)證時(shí)候字段的pre_validate 【預(yù)留的擴(kuò)展】字段的_run_validation_chain,對(duì)正則和字段的鉤子函數(shù)進(jìn)行校驗(yàn)字段的post_validate【預(yù)留的擴(kuò)展】 View Code?
作者:武沛齊出處:http://www.cnblogs.com/wupeiqi/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接。
?
轉(zhuǎn)載于:https://www.cnblogs.com/l-jie-n/p/10092576.html
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的Flask wtforms的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c/c++排坑(4) -- c/c++中
- 下一篇: 洛谷 P4660 bzoj 1168