Flask之Ajax提交WTF表单实例

48 篇文章 1 订阅
7 篇文章 0 订阅

以前写前端表单的时候,通常都是直接把表单里的一个个input写在html文件中,这样写form提交方式是可行的,但是对于表单的默认提交是不具有验证效果,除非把值传到后台再进行处理,这样一来其实还是很麻烦;如果采用ajax提交表单,则都需要对每个需要验证的进行正则匹配,然后判断再发起,也一样麻烦。还有一个缺点就是如果在网站中需要多个同样的表单,那么就需要在前端模板中写多个一模一样的form表单。要是有个form模型在想用的时候实例化一下就可以用该多好?

在flask中的WTF刚好可以解决这一问题,一般是建立一个存放form模型的文件form.py,然后在视图函数里进行实例化,再传到前端模板渲染,这样即便在多个地方需要同一个form表单,直接调用实例即可。用这种form模型不仅大大提高效率,还具有较好的表单验证。在前面的Flask实现登录、注册(邮箱验证)中也有写到关于WTF的表单提交,前面提到的用户注册、登录表单都是基于WTF的form模型创建的,这两个form都是submit默认提交到当前页,本文则是用ajax提交表单。

首先先写个我们需要的表单form模型,即在form.py文件中添加一下代码

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, ValidationError, RadioField, DateField, SelectField
from wtforms.validators import Required, Length, Email, Regexp, EqualTo
from app import label
class EditUserInfoForm(FlaskForm):
    """
    # Radio Box类型,单选框,choices里的内容会在ul标签里,里面每个项是(值,显示名)对
    gender = RadioField('Gender', choices=[('m', 'Male'), ('f', 'Female')],
                                  validators=[DataRequired()])
    """
    name = StringField(label('_user_name'),validators=[Required(),Regexp(r"^[\u4E00-\u9FA5]{2,4}$",
               message=label('_input_erro',['真实姓名']))])
    sex = RadioField(label('_sex'), coerce=int, choices=[(0, label('_male')), (1, label('_female'))])
    nickname = StringField(label('_nickname'),validators=[Required(),Regexp(r'^([A-Za-z]+\s?)*[A-Za-z]$',
        message=label('_input_erro',['英文名']))])
    email = StringField(label('_email'), validators=[Email(message=label('_input_erro',['邮箱']))])
    tel = StringField(label('_tel'),validators=[Required()])
    birthday = DateField(label('_birthday'),validators=[Required(message=label('_input_erro',['出生日期']))])
    submit = SubmitField(label('_update'))

其中label用于文字的提示函数,我们放在app目录下的__init__.py中初始化,代码如下:

from werkzeug.utils import import_string
def label(name, values=[], path=None):
    '''
        默认从app目录下的guide导入所需变量
            name 导入的数据变量名
            values 数据类型必须市列表,提示的动态内容
            path 为导入的路径
    '''
    path = ".".join(path.split(".")[:-1]) + ".guide:" if path else "app.guide:"
    msg = import_string(path + name)
    return msg.format(values) if len(values) else msg

并在同级目录下创建存放我们想要引用的文字或者字符(guide.py),其中命名自定义,代码如下:

_update_succ     = '''更新成功'''
_upload_succ     = '''上传成功'''
_sex             = '''性别'''
_male            = '''男'''
_female          = '''女'''
_user_name       = '''真实姓名'''
_nickname        = '''英文名'''
_email           = '''邮箱'''
_tel             = '''电话'''
_birthday        = '''出生日期'''
_update          = '''更新'''
_change_succ     = '''success'''
_change_erro     = '''error'''
_input_erro      ='''{0[0]}格式有误'''

当我们想调用(没)有占位符的时候,直接导入label,然后在指定的位置使用label函数,例如:

#无占位符
sex = RadioField(label('_sex'), coerce=int, choices=[(0, label('_male')), (1, label('_female'))])
#有占位符
name = StringField(label('_user_name'),validators=[Required(),Regexp(r"^[\u4E00-\u9FA5]{2,4}$",
               message=label('_input_erro',['真实姓名']))])

form模型建好之后,就是视图函数,实例化form表单,然后传到前端模板渲染,代码如下:

@auth.route('/information')
@login_required
def show_info():
    #实例化表单的值就是给表单填写默认值
    form = EditUserInfoForm(name=current_user.name,nickname=current_user.nickname,\
        email=current_user.email,tel=current_user.tel,birthday=current_user.birthday,sex=current_user.sex)

    return render_template('auth/users/information.html' form=form)

前端模板如下:

<form action="#" id="changeform" method="POST">
        {{ form.hidden_tag() }}
        <div class="form-body overflow-hide">
            <div class="form-group">
                <label class="control-label mb-10" for="exampleInputuname_1">{{ form.name.label }}</label>
                <div class="input-group">
                    {{ form.name(class="form-control", id='name', required="required") }}
                </div>
            </div>
            <div class="form-group">
                <label class="control-label mb-10">{{ form.sex.label }}</label>
                    <div class="radio">
                        {{ form.sex(required="required",class='sex-radio') }}
                    </div>
            </div>

            <div class="form-group">
                <label class="control-label mb-10" for="exampleInputEmail_1">{{ form.nickname.label }}</label>
    
                <div class="input-group">
                    {{ form.nickname(class="form-control", id='nickname', required="required") }}
                </div>
            </div>
            <div class="form-group">
                <label class="control-label mb-10" for="exampleInputuname_1">{{ form.email.label }}</label>
                <div class="input-group">
                {{ form.email(class="form-control", id='email', required="required") }}
                </div>
            </div>
            <div class="form-group">
                <label class="control-label mb-10" for="exampleInputuname_1">{{ form.tel.label }}</label>
                <div class="input-group">
                {{ form.tel(class="form-control",id='tel', required="required") }}
                </div>
            </div>
            <div class="form-group">
                <label class="control-label mb-10" for="exampleInputuname_1">{{ form.birthday.label }}</label>
                <div class="input-group">
                {{ form.birthday(class="form-control", id='birthday') }}
                </div>
            </div>
        </div>
        <div class="modal-footer">
        {{ form.submit(id="submit_btn", class="btn btn-success waves-effect", required="required") }}
        <button type="button" class="btn btn-default waves-effect" data-dismiss="modal">取消</button>
    </div>
</form>

jq的Ajax代码如下:

$(document).ready(function(){
  $('#submit_btn').on('click',function(e){
      //该命令时取消表单的默认提交
     //防止默认提交后跳转
      e.preventDefault()
      //用POST方法提交,把整个form提交到后台
      var post_data=$('#changeform').serialize();
      $.ajax({
              url:'updateinfo',
              method:'POST',
              dataType:'json',//后台返回json格式的返回值
              data:post_data,
              success:function(response){
               //如果想把后台返回回来的json对象转字符
              //用JSON.stringify(response)转字符
                for (var key in response){
                  // alert(response[key]);
                  console.log(response[key])
                  }
              })
          });
  });
});

后台请求接口代码如下:

@auth.route('/updateinfo', methods=['POST'])
@login_required
def update_info():
    '''
        ajax保存用户的修改信息
    '''
    name=request.form.get('name')
    nickname=request.form.get('nickname')
    sex=request.form.get('sex')
    email=request.form.get('email')
    tel=request.form.get('tel')
    birthday=request.form.get('birthday')
    form = EditUserInfoForm(name=name,nickname=nickname,email=email,tel=tel,birthday=birthday,sex=sex)
    if form.validate_on_submit():
        current_user.name=name
        current_user.nickname=nickname
        current_user.sex=int(sex)
        current_user.email=email
        current_user.tel=tel
        current_user.birthday=birthday
        db.session.add(current_user)
        result = {'success':label('_update_succ')}
    else:
        result = form.errors

    return json.dumps(result)

一开始form.validate_on_submit()不停的返回false,后来经过调试,才发现是因为在建立form模型的,对于性别的RadioField缺少一个属性,导致到后台始终不被识别,后来找到资料,在RadioField里面添加一个coerce属性才能运行成功。

sex = RadioField(label('_sex'), coerce=int, choices=[(0, label('_male')), (1, label('_female'))])

写代码还是要多总结多整理,不然下次再遇到这种很难找的错,估计又要折腾老半天才能解决。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值