本章涉及到的知识如下:

  • 表单类的概念,以及如何定义一个表单类

  • WTForms表单类验证表单功能,和使用表单类渲染模板的方法

  • 以及flask获取表单数据

  • 在form表单中做文件上传的方法

 

写在前面:用户提交一个表单,通常是以POST请求的方式发往服务器。服务器可以使用request.from获取其中的数据,然后在输入函数中对信息进行验证处理。。然而,每次都要手动完成逻辑验证这种方法太过繁琐。WTForms可以把表单数据的处理变成一种欢乐的体验!


正文:

一、WTForms

WTForms拓展包有两个功能,第一个就是做表单验证,把用户提交上来的数据进行验证是否合法。第二个就是做模版渲染。

Flask-WTF是简化了WTForms操作的一个第三方库

安装依赖:

pip install flask-wtf

 

1.做表单验证:

1. 自定义一个表单类,继承自wtforms.Form类。

2. 定义好需要验证的字段,字段的名字必须和模版中那些需要验证的input标签的name属性值保持一致。

3. 在需要验证的字段上,需要指定好具体的数据类型。

4. 在相关的字段上,指定验证器validators。

5. 以后在视图中,就只需要使用这个表单类的对象,并且把需要验证的数据,也就是request.form传给这个表单类,以后调用form.validate()方法,如果返回True,那么代表用户输入的数据都是合法的,否则代表用户输入的数据是有问题的。如果验证失败了,那么可以通过form.errors来获取具体的错误信息。

定义表单类:

class RegistForm(Form):
    username = StringField(validators=[Length(min=3,max=10,message='用户名长度必须在3到10位之间')])
    password = StringField(validators=[Length(min=6,max=10)])
    password_repeat = StringField(validators=[Length(min=6,max=10),EqualTo("password")])

 

视图函数中的处理,request.from进行初始化 -> form.validate表单类验证 -> 结果处理返回

form = RegistForm(request.form)
if form.validate():
    return "success"
else:
    print(form.errors)
    return "fail"

 

常用的验证器:

数据发送过来,经过表单验证,因此需要验证器来进行验证,以下对一些常用的内置验证器进行讲解:

  • 1. Email:验证上传的数据是否为邮箱。
  • 2. EqualTo:验证上传的数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等。
  • 3. InputRequir:原始数据的需要验证。如果不是特殊情况,应该使用InputRequired。
  • 3. Length:长度限制,有min和max两个值进行限制。
  • 4. NumberRange:数字的区间,有min和max两个值限制,如果处在这两个数字之间则满足。
  • 5. Regexp:自定义正则表达式。
  • 6. URL:必须要是URL的形式。
  • 7. UUID:验证UUID。

 

 

2.自定义验证器:

如果想要对表单中的某个字段进行更细化的验证,那么可以针对这个字段进行单独的验证。步骤如下:

  • 1. 定义一个方法,方法的名字规则是:`validate_字段名(self,filed)`。
  • 2. 在方法中,使用`field.data`可以获取到这个字段的具体的值。
  • 3. 如果数据满足条件,那么可以什么都不做。如果验证失败,那么应该抛出一个`wtforms.validators.ValidationError`的异常,并且把验证失败的信息传到这个异常类中。

 

python 对 captcha这个字段内容进行验证,如果不是'1234'就抛出异常,否则验证通过!

captcha = StringField(validators=[Length(4,4)])
    # 1234
    def validate_captcha(self,field):
        if field.data != '1234':
            raise ValidationError('验证码错误!')

 


二、文件上传

  • 1. 在模版中,form表单中,需要指定`encotype='multipart/form-data'`才能上传文件。
  • 2. 在后台如果想要获取上传的文件,那么应该使用`request.files.get('avatar')`来获取。
  • 3. 保存文件之前,先要使用`werkzeug.utils.secure_filename`来对上传上来的文件名进行一个过滤。这样才能保证不会有安全问题。 
  • 4. 获取到上传上来的文件后,使用`avatar.save(路径)`方法来保存文件。、
  • 5. 从服务器上读取文件,应该定义一个url与视图函数,来获取指定的文件。在这个视图函数中,使用`send_from_directory(文件的目录,文件名)`来获取。

python

@app.route('/upload/',methods=['GET','POST'])
def upload():
    if request.method == 'GET':
        return render_template('upload.html')
    else:
        # 获取描述信息
        desc = request.form.get("desc")
        avatar = request.files.get("avatar")
        filename = secure_filename(avatar.filename)
        avatar.save(os.path.join(UPLOAD_PATH,filename))
        print(desc)
        return '文件上传成功'

@app.route('/images/<filename>/')
def get_image(filename):
    return send_from_directory(UPLOAD_PATH,filename)

在对应的模板中配置如下:

<body>
<form action="" method="post" enctype="multipart/form-data">
    <table>
        <tbody>
            <tr>
                <td>头像:</td>
                <td><input type="file" name="avatar"></td>
            </tr>
            <tr>
                <td>描述:</td>
                <td><input type="text" name="desc"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交"></td>
            </tr>
        </tbody>
    </table>
</form>

 

如果要对上传文件使用表单验证

  • 1. 定义表单的时候,对文件的字段,需要采用`FileField`这个类型。
  • 2. 验证器应该从`flask_wtf.file`中导入。`flask_wtf.file.FileRequired`是用来验证文件上传是否为空。`flask_wtf.file.FileAllowed`用来验证上传的文件的后缀名。
  • 3. 在视图文件中,使用`from werkzeug.datastructures import CombinedMultiDict`来把`request.form`与`request.files`来进行合并。再传给表单来验证。

 

示例代码如下:

python

from werkzeug.datastructures import CombinedMultiDict
form = UploadForm(CombinedMultiDict([request.form,request.files]))

表单类配置

from flask_wtf.file import FileRequired,FileAllowed

class UploadForm(Form):
    avatar = FileField(validators=[FileRequired(),FileAllowed(['jpg','png','gif'])])
    desc = StringField(validators=[InputRequired()])

 

现在图片已经上传到服务器,用户如何通过服务器访问呢?

可以通过URL访问到,视图函数处理如下:

@app.route('/images/<filename>/')
def get_image(filename):
    return send_from_directory(UPLOAD_PATH,filename)