85flask之wtforms

布吉岛丶 布吉岛丶     2022-10-10     426

关键词:

本篇导航:

 

一、wtforms组件的使用

1、flask中的wtforms

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。

安装:

pip3 install wtforms

2、wtforms组件的使用之登录验证

1)图示

2)manage.py

from  flask import Flask,render_template,request,redirect
from  wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import Form
from wtforms import validators
from wtforms import widgets
app = Flask(__name__,template_folder="templates")

class Myvalidators(object):
    '''自定义验证规则'''
    def __init__(self,message):
        self.message = message
    def __call__(self, form, field):
        print(field.data,"用户输入的信息")
        if field.data == "haiyan":
            return None
        raise validators.ValidationError(self.message)

class LoginForm(Form):
    '''Form'''
    name = simple.StringField(
        label="用户名",
        widget=widgets.TextInput(),
        validators=[
            Myvalidators(message="用户名必须是haiyan"),#也可以自定义正则
            validators.DataRequired(message="用户名不能为空"),
            validators.Length(max=8,min=3,message="用户名长度必须大于%(max)d且小于%(min)d")
        ],
        render_kw={"class":"form-control"}  #设置属性
    )

    pwd = simple.PasswordField(
        label="密码",
        validators=[
            validators.DataRequired(message="密码不能为空"),
            validators.Length(max=8,min=3,message="密码长度必须大于%(max)d且小于%(min)d"),
            validators.Regexp(regex="\d+",message="密码必须是数字"),
        ],
        widget=widgets.PasswordInput(),
        render_kw={"class":"form-control"}
    )



@app.route('/login',methods=["GET","POST"])
def login():
    if request.method =="GET":
        form = LoginForm()
        return render_template("login.html",form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print("用户提交的数据用过格式验证,值为:%s"%form.data)
            return "登录成功"
        else:
            print(form.errors,"错误信息")
        return render_template("login.html",form=form)


if __name__ == '__main__':
    # app.__call__()
    app.run(debug=True)
View Code

3)login.html

<body>
<form action="" method="post" novalidate>
    <p>{{ form.name.label }} {{ form.name }} {{ form.name.errors.0 }}</p>
    <p>{{ form.pwd.label }} {{ form.pwd }} {{ form.pwd.errors.0 }}</p>
    <input type="submit" value="提交">
    <!--用户名:<input type="text">-->
    <!--密码:<input type="password">-->
    <!--<input type="submit" value="提交">-->
</form>
</body>

3、wtforms组件的使用之用户注册

1)图示

2)manage.py

from flask import Flask,render_template,redirect,request
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 widgets

app = Flask(__name__,template_folder="templates")
app.debug = True

=======================simple===========================
class RegisterForm(Form):
    name = simple.StringField(
        label="用户名",
        validators=[
            validators.DataRequired()
        ],
        widget=widgets.TextInput(),
        render_kw={"class":"form-control"},
        default="haiyan"
    )
    pwd = simple.PasswordField(
        label="密码",
        validators=[
            validators.DataRequired(message="密码不能为空")
        ]
    )
    pwd_confim = simple.PasswordField(
        label="重复密码",
        validators=[
            validators.DataRequired(message='重复密码不能为空.'),
            validators.EqualTo('pwd',message="两次密码不一致")
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

  ========================html5============================
    email = html5.EmailField(  #注意这里用的是html5.EmailField
        label='邮箱',
        validators=[
            validators.DataRequired(message='邮箱不能为空.'),
            validators.Email(message='邮箱格式错误')
        ],
        widget=widgets.TextInput(input_type='email'),
        render_kw={'class': 'form-control'}
    )

  ===================以下是用core来调用的=======================
    gender = core.RadioField(
        label="性别",
        choices=(
            (1,""),
            (1,""),
        ),
        coerce=int  #限制是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):  #这里的self是一个RegisterForm对象
        '''重写__init__方法'''
        super(RegisterForm,self).__init__(*args, **kwargs)  #继承父类的init方法
        self.favor.choices =((1, '篮球'), (2, '足球'), (3, '羽毛球'))  #吧RegisterForm这个类里面的favor重新赋值

    def validate_pwd_confim(self,field,):
        '''
        自定义pwd_config字段规则,例:与pwd字段是否一致
        :param field:
        :return:
        '''
        # 最开始初始化时,self.data中已经有所有的值
        if field.data != self.data['pwd']:
            # raise validators.ValidationError("密码不一致") # 继续后续验证
            raise validators.StopValidation("密码不一致")  # 不再继续后续验证

@app.route('/register',methods=["GET","POST"])
def register():
    if request.method=="GET":
        form = RegisterForm(data={'gender': 1})  #默认是1,
        return render_template("register.html",form=form)
    else:
        form = RegisterForm(formdata=request.form)
        if form.validate():  #判断是否验证成功
            print('用户提交数据通过格式验证,提交的值为:', form.data)  #所有的正确信息
        else:
            print(form.errors)  #所有的错误信息
        return render_template('register.html', form=form)

if __name__ == '__main__':
    app.run()
View Code

3)register.html

<body>
<h1>用户注册</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>

4、mate

#!/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 md5

app = Flask(__name__, template_folder='templates')
app.debug = True


class MyCSRF(CSRF):
    """
    Generate a CSRF token based on the user's IP. I am probably not very
    secure, so don't use me.
    """

    def setup_form(self, form):
        self.csrf_context = form.meta.csrf_context()
        self.csrf_secret = form.meta.csrf_secret
        return super(MyCSRF, self).setup_form(form)

    def generate_csrf_token(self, csrf_token):
        gid = self.csrf_secret + self.csrf_context
        token = md5(gid.encode('utf-8')).hexdigest()
        return token

    def 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
        # 是否自动生成CSRF标签
        csrf = True
        # 生成CSRF标签name
        csrf_field_name = 'csrf_token'

        # 自动生成标签的值,加密用的csrf_secret
        csrf_secret = 'xxxxxx'
        # 自动生成标签的值,加密用的csrf_context
        csrf_context = lambda x: request.url
        # 生成和比较csrf标签
        csrf_class = MyCSRF

        # -- i18n
        # 是否支持本地化
        # locales = False
        locales = ('zh', 'en')
        # 是否对本地化进行缓存
        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

 

二、自定义Form组件

1、wtforms源码流程

1)实例化流程分析

# 源码流程
    1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中
    2. 执行构造方法
        
        a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。
            即:
                _fields = {
                    name: wtforms.fields.core.StringField(),
                }
                
            PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField()
        
        b. 循环_fields,为对象设置属性
            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. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs)
            优先级:obj,data,formdata;
            
            再循环执行每个字段的process方法,为每个字段设置值:
            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)
            
            执行每个字段的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.default
        
                self.object_data = data
        
                try:
                    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. 页面上执行print(form.name) 时,打印标签
            
            因为执行了:
                字段的 __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)
                执行字段的插件对象的 __call__ 方法,返回标签字符串
View Code

2)验证流程分析

a. 执行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. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数)
            def validate(self, extra_validators=None):
                self._errors = None
                success = True
                for 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 = False
                return success
        c. 每个字段进行验证时候
            字段的pre_validate 【预留的扩展】
            字段的_run_validation_chain,对正则和字段的钩子函数进行校验
            字段的post_validate【预留的扩展】
View Code

2、自定义Form组件

#!usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask,render_template,request,Markup
app = Flask(__name__,template_folder="templates")
app.debug = True
# ==============通过这几个类就可以显示了-==============
#插件
class Widget(object):
    pass

class InputText(Widget):
    def __call__(self, *args, **kwargs):

        return "<input type='text' name='name'>"

class TextArea(Widget):
    def __call__(self, *args, **kwargs):
        return Markup("<textarea name='email'></textarea>")

#Form
class BaseForm(object):
    def __init__(self):
        #获取当前所有的字段
        _fields = {}
        for name, field in self.__class__.__dict__.items():
            if isinstance(field, Field):  # 筛选出字段是name和emailDe
                _fields[name] = field
        self._fields = _fields
        self.data = {}
        # print(_fields)  # {'name': 111, 'email': 222}

    def validate(self,request_data):
        #先找到所有的字段,在执行每一个字段的validate方法
        flag = True
        for name, field in self._fields.items():
            input_val = request_data.get(name,"") #用户输入的值
            result= field.validate(input_val)  #每一个字段自己校验
            print("???????????",input_val,result)
            if not result:
                flag = False
            else:
                self.data[name] = input_val
        return flag
#字段
class Field(object):
    '''所有类的基类'''
    def __str__(self):          #python中的静态字段通过类能找到,通过对象也能找到
        return Markup(self.widget())  #self就是StringField,self

class StringField(Field):  #每个字段打印的时候都要去执行__str__,所以选择放在基类里面,自己没有就调用父类的
    widget = InputText()
    def validate(self,val):
        if val:
            return True

class EmaliField(Field):
    widget = TextArea()
    reg = ".*@.*"

    def validate(self,val):
        import re
        print(re.match(self.reg,val),"************")
        if re.match(self.reg,val):
            return True


# ===============使

flask之wtforms验证

...供了前端表单自动生成和前端表单提交数据验证的功能。WTForms支持的HTML标准字段字段对象说明StringField文本字段TextAreaField多行文本字段PasswordField密码文本字段HiddenField隐藏文本字段DateField文本字段,值为datetime.date格式 查看详情

flask之wtforms

 简介WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装:1pip3installwtforms用户登录注册示例1.用户登录当用户登录时候,需要对用户提交的用户名和密码进行多种格式校验。如:用户不能为空;... 查看详情

flask之wtforms源码分析

一、wtforms源码流程1、实例化流程分析1#源码流程21.执行type的__call__方法,读取字段到静态字段cls._unbound_fields中;meta类读取到cls._wtforms_meta中32.执行构造方法45a.循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值... 查看详情

6---flask-wtforms(代码片段)

6、Flask-WTForms Flask-WTF是简化了WTForms操作的一个第三方库。WTForms表单的两个主要功能是验证用户提交数据的合法性以及渲染模板。还有其它一些功能:CSRF保护,文件上传等。安装方法:pipinstallflask-wtf1.1.WTForms简单验证fromflaski... 查看详情

Flask-WTForms 在我的项目目录中找不到 WTForms

】Flask-WTForms在我的项目目录中找不到WTForms【英文标题】:Flask-WTFormscan\'tfindWTFormsinmyprojectdirectory【发布时间】:2012-07-2708:38:54【问题描述】:这是我在***上的第一篇文章,大家好。我正在做博客应用程序来学习Python和Flask,我想... 查看详情

flask第七篇flask中的wtforms使用

一、简单介绍flask中的wtformsWTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装:pip3installwtforms二、简单使用wtforms组件1、用户登录具体代码:fromflaskimportFlask,render_template,request,redirectfromwtforms.fieldsimp... 查看详情

flask中的wtforms使用(代码片段)

一、简单介绍flask中的wtformsWTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装:pip3installwtforms二、简单使用wtforms组件1、用户登录具体代码:fromflaskimportFlask,render_template,request,redirectfromwtforms.fieldsimp... 查看详情

flask-flask-script|多app应用|wtforms

flask-script用于实现类似于django中python3manage.pyrunserver...类似的命令安装>:pip3installflask-script使用manage.pyfromflaskimportFlask#1.导入Managerfromflask_scriptimportManager#2.实例化Flask生成对象appapp=Flask(__name__)#3 查看详情

flask-wtforms

what‘sthe WTForms  WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。其作用是可以为轻量级的框架提供类似Django的form的功能。安装:pip3installwtforms 源码流程分析实例化流程分析#源码流程1.执行typ... 查看详情

wtformsinflask(wtforms在flask中的应用)(代码片段)

WTFormsWTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装wtforms:pip3/pipinstallwtforms 用户登录/注册示例项目目录结构flask-wtforms-example│app.py│└─templatesadd_user.htmlindex.htmllogin.htmlregister.htmlusers.html& 查看详情

flask框架:运用wtforms实现用户注册(代码片段)

WTForms是用于web开发的灵活的表单验证和呈现库,它可以与您选择的任何web框架和模板引擎一起工作,并支持数据验证、CSRF保护、国际化等,运用WTForms框架并配合Flask可实现一个带有基本表单验证功能的用户注册与登录页面,经... 查看详情

使用 WTForms 字段列表

】使用WTForms字段列表【英文标题】:WorkingwithWTFormsFieldList【发布时间】:2011-08-2510:17:22【问题描述】:我通过Flask.WTF扩展将WTForms与Flask一起使用。不过,这个问题不是Flask特有的。WTForms包含一个FieldListfieldforlistsoffields。我想用... 查看详情

动态选择 WTForms Flask SelectField

】动态选择WTFormsFlaskSelectField【英文标题】:DynamicchoicesWTFormsFlaskSelectField【发布时间】:2018-04-0522:01:45【问题描述】:我正在尝试使用FlaskForms将userID变量传递给WTForms。首先,我将展示可以正常工作的代码,然后是我需要修改的... 查看详情

flask--wtforms(代码片段)

简介WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装:pip3installwtforms用户登录注册示例1.用户登录当用户登录时候,需要对用户提交的用户名和密码进行多种格式校验。如:用户不能为空;用户... 查看详情

flask:flask-script;多app应用;wtforms;sqlchmy

一. flask-script一.flask-script简介1.什么是flask-script:是一个让你的命令行支持自定义命令的工具,它为Flask程序添加一个命令行解释器。可以让我们的程序从命令行直接执行相应的程序(用于实现类似于django中python3manage.pyrunserver...... 查看详情

flask学习第7篇:flask中的wtforms使用(代码片段)

flask中的wtforms使用一、简单介绍flask中的wtformsWTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。安装:pip3installwtforms二、简单使用wtforms组件1、用户登录具体代码:fromflaskimportFlask,render_template,request,redir... 查看详情

wtforms快速使用和源码分析(基于flask)

wtforms和django的form组件大同小异,下面给出一个应用举例以便快速查询。开始使用1fromflaskimportFlask,render_template,request,redirect23fromwtformsimportForm45fromwtforms.fieldsimportcore6fromwtforms.fieldsimporthtml57fromwtforms.fie 查看详情

自动完成 Flask wtforms

】自动完成Flaskwtforms【英文标题】:AutocompleteFlaskwtforms【发布时间】:2021-03-0413:59:44【问题描述】:我想使用数量和商品价格自动更新我的总金额字段?有没有办法使用没有javascript的烧瓶来做到这一点?我希望在输入数量和商... 查看详情