第4章 表单与类视图

学习目标

  • 熟悉Flask处理表单的方式,能够归纳在Flask程序中如何处理表单

  • 掌握Flask-WTF扩展包的安装,能够借助pip工具安装Flask-WTF扩展包

  • 掌握使用Flask-WTF创建表单的方式,能够独立使用Flask-WTF创建表单

  • 掌握在模板中渲染表单的方式,能够在模板文件中渲染使用Python类定义的表单

  • 掌握Flask-WTF验证表单的方式,能够通过validate_on_submit()方法验证表单,并在模板文件中输出错误提示信息

  • 掌握类视图的定义方式,能够定义标准类视图和基于请求方法的类视图

  • 掌握蓝图的使用,能够利用蓝图对Flask程序进行模块化拆分

在Web程序中,表单是与用户进行交互的方式之一,常见于用户注册、用户登录、编辑设置等页面。不过处理表单是比较麻烦的,涉及创建表单、验证表单数据、获取和保存表单数据、反馈错误提示等诸多操作,为了降低开发人员处理表单的难度,Flask提供了专门负责处理表单的扩展包——Flask-WTF。另外,Flask还提供了类视图和蓝图。接下来,本章主要针对表单与类视图的相关内容进行讲解。

4.1 通过Flask处理表单

表单是在网页中搜集用户信息的各种表单控件的集合区域,表单控件包括文本框、单选框、复选框、提交按钮等,用于实现客户端和服务器端之间的数据交互。通过表单搜集的用户输入的敏感信息,比如用户名、密码等,一般会通过POST请求的方式提交给服务器进行处理,安全性相对更高。

在Flask程序中,我们可以利用Flask内置的部分功能对表单进行简单的处理,具体的处理过程:首先在模板文件中通过HTML代码创建表单,然后通过请求上下文中的request.form对象获取以及验证表单数据,最后通过消息闪现给用户反馈正确或错误提示。

通过用户注册的案例分步骤为大家演示如何使用Flask内置的功能处理表单,具体步骤如下。

(1)创建一个Flask项目Chapter04,在Chapter04项目中新建templates文件夹,在该文件夹下创建模板文件register.html,在该模板文件中使用form标签创建表单。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
</head>
<body><h1>注册页面</h1>{#给用户展示不同的消息闪现#}{% macro print_error(type) %}{% for message in get_flashed_messages(category_filter = (type)) %}<p class="error" style="color: red;display:inline;">{{ message }}</p>{% endfor %}{% endmacro %}<form action="" method=post><span>用户名:</span><br><input type=text name=username>{{ print_error('message') }}{{ print_error('info') }}<br><span>密码:</span><br><input type=password name=password><br><span>确认密码:</span><br><input type=password name=password2>{{ print_error('error') }}<br><p><input type=submit value=注册></p></form>
</body>
</html>

(2)在app.py文件中定义视图函数register(),该视图函数用于展示注册页面以及验证用户输入的注册数据是否符合要求。

from flask import Flask, render_template, request, flash
app = Flask(__name__)
app.secret_key = 'Your_seccret_key&^52@!'
@app.route('/register', methods=['GET', 'POST'])
def register():# 判断请求方式if request.method == 'POST':# 获取表单数据username = request.form.get('username')password = request.form.get('password')password2 = request.form.get('password2')# 验证数据的完整性if not all([username, password, password2]):flash('请填入完整信息', category='message')# 验证输入的数据是否符合要求elif len(username) < 3 and len(username) > 0 or len(username) > 15:flash('用户名长度大于3且小于15', category='info')# 验证两次输入的密码是否一致elif password != password2:flash('密码不一致', category='error')else:return '注册成功'return render_template('register.html')
if __name__ == '__main__':app.run()

(3)运行代码,通过浏览器访问http://127.0.0.1:5000/register后展示了注册页面。

单击“注册”按钮后,注册页面上用户名输入框的后面展示了提示信息“请填入完整信息”。

密码为“123”,确认密码为“123”,单击“注册”按钮后,注册页面上用户名输入框的后面展示了提示信息“用户名长度大于3且小于15”。

依次填写用户名为“666666”,密码为“123”,确认密码为“123456”,单击“注册”按钮后,注册页面上确认密码输入框的后面展示了提示信息“密码不一致”。

4.2 通过FLask-WTF处理表单

4.2.1 安装Flask-WTF扩展包

Flask-WTF是Flask中专门用于处理表单的扩展包,该扩展包内部对Flask和WTForms进行了一个简单的集成,可以让开发者便捷地使用WTForms来处理表单。 WTForms其实是一个灵活的表单验证和渲染库,可以与Flask、Django等多个Web框架结合使用,支持表单数据验证、CSRF保护、国际化等功能。 要想在Flask程序中使用Flask-WTF扩展包,需要提前在虚拟环境中进行安装。我们可以通过pip命令安装Flask-WTF扩展包。

 (flask_env) E:\env_space>pip install flask-wtf

4.2.2 使用Flask-WTF创建表单

Flask-WTF的表单其实是一个继承FlaskForm的类,表单类中可以根据需要包含若干个属性,每个属性的值又是一个表单字段类的对象,不同字段类的对象会映射为表单中的不同控件。

WTForms库的Field类派生了许多表单字段类,常用字段类与表单控件的映射关系。

字段类表单控件说明
BooleanFieldinput type="checkbox"复选框,值为True或False,默认值为Flase
DataFieldinput type="text"文本字段,值为datetime.date对象
DataTimeFieldinput type="text"文本字段,值为datetime.datetime对象
DecimalFieldinput type="text"文本字段,值为decimal.Decimal
FileFieldinput type="file"文件上传字段
FloatFieldinput type="text"浮点数字段,值为浮点型
IntegerFieldinput type="text"整数字段,值为整型
字段类表单控件说明
RadioFieldinput type="radio"一组单选按钮
SelectFieldselect option /option /select下拉列表
SubmitFieldinput type="submit"提交按钮
StringFieldinput type="text"文本字段
PasswordFieldinput type="password"密码文本字段
TextAreaFieldtextarea /textarea多行文本字段
HiddenFieldinput type="hidden"隐藏文本字段

常用的字段类都继承自WTForms库的Field类,所以我们可以通过Field类的构造方法实例化所有字段类,虽然有的字段类内部已经重写了Filed类的构造方法,但这些字段类的构造方法中会包含一些相同的参数。

参数说明
label字段标签<label>的值,即显示在输入控件旁的说明性文字
render_kw字典类型,用于设置控件的属性
validators列表类型,包含一系列的验证器,在提交表单数据时,会被列表中的验证器逐一验证
default字符串或可调用对象,为表单字段设置默认值

参数render_kw的值是一个字典,用于为表单控件设置一些属性,包括提示信息(placeholder)、高度(height)、宽度(width )、是否获得焦点(autofocus )等。

参数validators的值是一个列表,该列表中包含了一系列用于验证表单数据是否有效的验证器,只有当表单数据满足验证器的规则时,填写的表单数据才能成功提交到服务器。 在WTForms库中,验证器是一些用于字段数据的Python类,这些类都封装在wtforms.validators模块中,因此我们在使用验证器之前需要先从wtforms.validators模块中导入相应的类。

验证器说明
DataRequired(message=None)验证数据是否有效,空字符串是为无效数据
Email(message=None)验证数据是否为电子邮件地址
EqualTo(fieldname,message=None)验证两个字段值是否相同
IPAddress(ipv4=True, ipv6=False, message=None)验证数据是否为有效IP地址
Length(min=-1,max=-1,message=None)验证输入值的长度是否在给定的范围内
NumberRange(min=None,max=None,message=None)验证输入的数字是否在给定的范围内
验证器说明
Optional(strip_whitespace=True)无输入值时跳过其他验证
Regexp(regex,flags=0,message=None)使用正则表达式验证输入值
URL(require_tld=True,message=None)验证URL
AnyOf(values, message=None,values_formatter=None)确保输入值在可选值列表中
NoneOf(values, message=None,values_formatter=None)确保输入值不在可选值列表中
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
app = Flask(__name__)
class RegisterForm(FlaskForm):username = StringField(label='用户名:',validators=[DataRequired(message='用户名不能为空'),Length(3, 15, message='长度应该为3~15')])password = PasswordField('密码:',validators=[DataRequired(message='密码不能为空')])password2 = PasswordField('确认密码:',validators=[DataRequired(message='密码不能为空'),EqualTo('password', message='两次密码不一致')])submit = SubmitField('注册')

4.2.3 在模板中渲染表单

使用Flask-WTF创建了注册表单,但此时在模板文件中还无法渲染创建的表单。如果希望在模板文件中渲染通过Flask-WTF创建的表单,首先需要在视图函数中将表单类的对象传递到模板文件中,然后在模板文件中获取表单字段,将表单字段渲染到HTML页面进行呈现。

通过一个案例分步骤演示如何通过Flask-WTF在模板文件中渲染表单,具体步骤如下。 (1)在Chapter04项目的app.py文件中定义用于传递表单类对象的视图函数。

app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():form = RegisterForm()return render_template('register_wtf.html', form=form)
if __name__ == '__main__':app.run()

需要注意的是,默认情况下Flask-WTF为每个表单启用CSRF保护,因此我们需要在程序中设置密钥,这样可以让Flask-WTF通过该密钥生成CSRF令牌,以便用CSRF令牌验证请求中表单数据的真伪。

(2)在templates文件夹中创建模板文件register_wtf.html,并在该模板文件中获取表单字段。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
</head>
<body><h1>注册页面</h1><form method="post">{{ form.csrf_token }}{#获取username对应的标签名称#}<span>{{ form.username.label }}</span><br>{#调用表单字段渲染为HTML#}{{ form.username }}<br><span>{{ form.password.label }}</span><br>{{ form.password }}<br><span>{{ form.password2.label }}</span><br>{{ form.password2 }}<br><p>{{ form.submit }}</p></form>
</body>
</html>

(3)运行代码,通过浏览器访问http://127.0.0.1:5000/register后页面中展示了通过Flask-WTF创建的注册表单。

多学一招:开启CSRF保护

CSRF指跨站请求伪造(Cross-site request forgery),是一种挟持用户在当前已登录的Web应用程序上执行非本意操作的攻击方法,它利用的是网站对用户浏览器的信任。 若网站中未开启CSRF保护,那么攻击者可通过一些非法技术手段盗用用户的身份信息,然后以用户的名义发送请求来进行一些恶意操作,例如,盗取用户账号进行转账、购买商品、发送信息等,造成个人隐私泄露和财产损失。

Flask-WTF提供了一套完善的CSRF保护体系,对于开发人员来说,使用非常起来简单。Flask-WTF中的CSRF保护体系由flask_wtf模块中的CSRFProtect类提供,该模块不仅能为包含表单的视图提供CSRF保护,还可以为不包含表单的视图提供CSRF保护(通过AJAX 发送POST请求可不用表单)。 在Flask程序中开启CSRF保护需要分别在后端和前端模板文件中进行设置。在Flask程序后端开启CSRF保护。

from flask_wtf.csrf import CsrfProtect   
app = Flask(__name__)
CsrfProtect(app)

需要注意的是,开启CSRF保护需要密钥对令牌进行安全签名。默认情况下,使用Flask应用程序的密钥secret_key,也可以通过设置WTF_CSRF_SECRET_KEY使用其他的密钥。 在前端模板文件的form标签中需要调用表单对象的csrf_token()方法。

<form method="post" action="/">{{ form.csrf_token }}
</form>

当CSRF验证失败时,默认会返回400的错误响应。

4.2.4 使用Flask-WTF验证表单

验证表单数据是网站对用户提交的表单数据的正确性进行校验。表单数据的验证通常分为两种形式,分别是客户端验证和服务器端验证。

客户端验证是指客户端(比如浏览器)对用户提交的数据进行校验。客户端验证一般可以通过多种方式进行验证,包括使用HTML5内置的验证属性、JavaScript表单验证库等。客户端验证可以实时动态提示用户输入是否正确,只有用户输入正确后才会将表单数据发送给服务器。

服务器端验证是指用户把表单数据提交到服务器端,由服务器端对表单数据进行校验。在服务器端校验时,若出现错误,则会将错误信息加入到响应进行返回,待用户修改后再次提交表单数据,直至通过校验为止。

Flask-WTF的FlaskForm类中提供了用于验证表单数据的validate_on_submit()方法,该方法内部会调用表单验证器对表单数据进行验证。

validate_on_submit()方法的返回值是一个布尔值,若返回值为True,则表示用户提交的表单数据符合验证器定义的规则,说明通过验证;若返回值为False,则用户提交的表单数据不符合验证器定义的规则,说明未通过验证。

针对未通过验证的情况,FlaskForm会将错误消息添加到表单类的errors属性中,errors属性的值是一个匹配表单字段类属性到错误信息列表的字典。若需要获取具体的错误信息列表,则可以在模板文件中通过“form.字段名. errors”进行获取。

通过一个案例分步骤演示如何通过Flask-WTF实现表单数据验证的功能,具体步骤如下。 (1)在Chapter04项目的app.py文件中,使用Flask-WTF扩展包创建表单,具体代码如下所示。

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
class RegisterForm(FlaskForm):username = StringField(label='用户名:', render_kw={'required': False},validators=[DataRequired(message='用户名不能为空'),Length(3, 15, message='长度应该为3~15')])password = PasswordField('密码:', render_kw={'required': False},validators=[DataRequired(message='密码不能为空')])password2 = PasswordField('确认密码:', render_kw={'required': False},validators=[DataRequired(message='密码不能为空'),EqualTo('password', message='两次密码不一致')])submit = SubmitField('注册')

(2)定义视图函数register(),对用户提交的表单数据进行验证。

app = Flask(__name__)
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():form = RegisterForm()if form.validate_on_submit():return '注册成功!'return render_template('register_wtf.html', form=form)
if __name__ == '__main__':app.run()

(3)在Chatper04项目的templates目录下新建模板文件register_verification.html,该模板文件中获取表单字段的错误消息

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
</head>
<body><h1>注册页面</h1><form method="post">{# 定义宏循环遍历错误信息列表#}{% macro print_error(form_fields) %}{% for error_message in form_fields %}<p class="error" style="color: red;display:inline;" >{{ error_message }}</p>{% endfor %}{% endmacro %}{{ form.csrf_token }}<span>{{ form.username.label }}</span><br>{{ form.username }}{{ print_error(form.username.errors) }}<br><span>{{ form.password.label }}</span><br>{{ form.password }}{{ print_error(form.password.errors) }}<br><span>{{ form.password2.label }}</span><br>{{ form.password2 }}{{ print_error(form.password2.errors) }}<br><p>{{ form.submit }}</p></form>
</body>
</html>

(4)重启开发服务器,通过浏览器访问http://127.0.0.1:5000/register后页面中展示了注册表单,在注册表单中不输入任何内容,单击“注册”按钮会在每个输入框后面提示错误信息。

4.3 类视图

4.3.1 标准类视图

在Flask中,标准类视图是继承flask.views模块中基类View的子类,该子类中必须重写View类中的dispatch_request()方法。除dispatch_request()方法外,我们也可以根据需要向View子类中添加其他方法或属性。

methods属性:设置当前类视图可以处理的请求方式列表。 decorators属性:为类视图指定装饰器列表,该列表中可以放置一个或多个装饰器。 dispatch_request()方法:用于实现处理不同HTTP请求的具体逻辑,该方法可以通过关键字参数接收URL传递的参数。 as_view()方法:用于将类转换为可与路由系统一起使用的实际视图函数。as_view()方法必须传入一个name参数,用于指定动态生成视图函数的名称,也可以根据需要传入一些位置参数和关键字参数,这些参数都会转发给类的构造方法,以创建类的实例,并调用类内部的dispatch_request()方法。

如果希望类视图能够对浏览器发送的HTTP请求进行处理,那么需要将类视图与URL建立映射关系。我们需要通过add_url_rule()方法将类视图与URL进行映射,不过该方法的view_func参数不能直接传入类视图的名称,而是需要传入通过as_view()方法将类视图转换后的视图函数。

from flask import Flask, request
from flask.views import Viewclass MyView(View):                             # 定义类视图def dispatch_request(self, name):        # 重写dispatch_request()方法return f'hello {name}'app = Flask(__name__)
# 将类视图与URL规则进行映射
app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview'))
if __name__ == '__main__':app.run()

运行代码,通过浏览器访问http://127.0.0.1:5000/hello/flask后页面中展示了类视图中dispatch_request()方法返回的内容。

在类视图中通过methods属性设置当前类视图可以处理的请求方式。例如,在上述示例的MyView类中,设置当前类视图可以处理GET请求和POST请求,并在dispatch_request()方法中添加处理GET请求的具体逻辑。

from flask import Flask, request
from flask.views import View# class MyView(View):                             # 定义类视图
#     def dispatch_request(self, name):        # 重写dispatch_request()方法
#         return f'hello {name}'class MyView(View):                              # 定义类视图methods = ['GET', 'POST']                   # 指定请求方式def dispatch_request(self, name):         # 重写dispatch_request()方法if request.method == 'GET':return f'hello {name}'
app = Flask(__name__)
# 将类视图与URL规则进行映射
app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview'))
if __name__ == '__main__':app.run()

4.3.2 基于方法的类视图

在Flask中,基于方法的类视图需要继承flask.views模块中的MethodView类,而MethodView类继承View类,由于MethodView类中已经重写了dispatch_request()方法,所以定义基于请求方法的类视图时不需要重写dispatch_request()方法。

在基于方法的类视图中,并非通过类属性methods来指定当前视图可以处理的请求方式,而是通过定义与请求方式同名的方法来处理不同的请求。例如,定义一个基于方法的类视图LoginView,之后在该类中添加处理GET请求和POST请求的方法。

from flask.views import MethodView
class LoginView(MethodView):def get(self):                                       # 处理GET请求return '我负责处理GET请求'def post(self):   	                      # 处理POST请求return '我负责处理POST请求'

基于方法的类视图同样需要使用add_url_rule()方法将类视图与URL规则进行映射,并将通过as_view()方法将类视图转换后的视图函数传入view_func参数。

通过一个用户登录案例分步骤演示如何定义与使用基于方法的类视图,具体步骤如下所示。 (1)在templates文件夹中添加一个用于展示用户登录页面的模板文件login.html。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
</head>
<body><form action="" method=post><span>用户名:</span><br><input type="text" name="username"><br><span>密码:</span><br><input type="password" name="password"><br><p><input type="submit" value="登录"></p></form>
</body>
</html>

(2)在app.py文件中定义与使用基于方法的类视图。

from flask.views import MethodView
from flask import Flask, render_template, request
class LoginView(MethodView):def get(self):                                       # 处理GET请求return render_template('login.html')def post(self):                         # 处理POST请求username = request.form.get('username')     # 获取输入的用户名password = request.form.get('password')     # 获取输入的密码# 判断用户名和密码是否为123if username =='flask' and password == '123':return f'用户:{username}登录成功。'else:return '用户名或密码错误,请重新登录。'
app = Flask(__name__)
app.add_url_rule('/login', view_func=LoginView.as_view('login'))
if __name__ == '__main__':app.run()

(3)运行代码,通过浏览器访问http://127.0.0.1:5000/login后页面中展示了用户登录表单。

依次在用户输入框和密码输入框中输入正确的用户名和密码,单击“登录”按钮后页面中展示了登录成功的提示信息。

4.4 蓝图

Flask推出了蓝图的概念,蓝图提供了模块化管理的功能,简化了大型Web应用程序的开发难度。 蓝图是一种制作应用程序组件的方式,可以在应用程序内部或跨越多个项目使用。当分配请求时,Flask会将蓝图和视图函数关联起来,并生成两个端点之前的URL。

蓝图适用于以下场景:

将一个应用程序分解成一组子模块。这是大型应用程序的理想选择,即项目实例化一个应用实例,初始化一些扩展,以及注册一组蓝图。 以一个URL前缀或子域在应用程序中注册蓝图。URL前缀或子域的参数成为该蓝图中所有视图函数的通用视图参数(具有默认值)。 在一个应用程序中用不同的URL规则多次注册一个蓝图。 通过蓝图提供模板过滤器、静态文件、模板和其他实用程序。蓝图不必实现应用程序或视图的功能。 在初始化Flask 扩展时在应用程序中注册一个蓝图。

若想在Flask程序中使用蓝图,首先需要创建蓝图,然后再对蓝图进行注册,其中创建蓝图需要通过Blueprint类实现;注册蓝图需要通过register_blueprint()方法实现。

假设Flask程序包含4个视图函数,分别属于普通用户和管理员两个子模块。如果在该程序中使用蓝图,那么使用蓝图前后的程序结构分别如下图。

1.创建蓝图

使用Blueprint类的构造方法可以创建蓝图,蓝图中也可以定义路由,定义方式与在Flask实例中定义路由的方式相同。

flask.Blueprint(name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, cli_group=<object object>)

name:必选参数,表示蓝图的名称。 import_name:必选参数,表示蓝图包的名称,通常为name。 static_folder:可选参数,表示静态文件夹的路径。 static_url_path:可选参数,表示静态文件的URL。 template_folder:可选参数,表示模板文件夹路径。 url_prefix:可选参数,表示附加到所有蓝图URL的路径,用于与Flask应用程序的其他URL区分。

在Chapter04项目的根目录下创建两个py文件,分别是user.py和admin.py,在这两个文件中分别创建user蓝图和admin蓝图。

2.注册蓝图

register_blueprint()方法用于将蓝图注册到Flask程序中。

register_blueprint(blueprint, url_prefix, subdomain, url_defaults,**options)

blueprint:必选参数,表示要注册的蓝图。 url_prefix:可选参数,表示附加到所有蓝图URL的路径,若在Blueprint类设置参url_prefix,则会被该参数值覆盖。

在Chapter04项目的app.py文件中使用register_blueprint()方法注册user蓝图和admin蓝图。

from admin import admin
from user import user
from flask import Flask
app = Flask(__name__)
app.register_blueprint(admin, url_prefix='/admin')  # 将蓝图admin进行注册
app.register_blueprint(user, url_prefix='/user')    # 将蓝图user进行注册
if __name__ == '__main__':app.run()

运行代码,通过浏览器分别访问http://127.0.0.1:5000/user/login或http://127.0.0.1:5000/admin/login后页面中显示的效果如下所示。

4.5 本章小结

本章首先介绍了通过Flask处理表单;然后介绍了通过Flask-WTF处理表单,包括安装Flask-WTF扩展包、使用Flask-WTF创建表单、在模板中渲染表单、通过Flask-WTF验证表单;接着介绍了类视图,包括标准类视图和基于方法的类视图;最后介绍了Flask中的蓝图。通过本章的学习希望读者能够掌握Flask中表单与类视图的使用,为后续的学习奠定扎实的基础。

4.6 习题

一,填空题

1.Flask中标准类视图需要继承flask.views模块中的()类。

2.定义标准类视图时需要重写()方法。

3.Flask中基于方法的类视图需要继承flask.views模块中的()类。

4.在Flask程序中,注册蓝图需要使用()方法。

5.在模板文件中可通过()获取CSRF令牌。

二,判断题

1.Flask-WTF是Flask内置的扩展包,无须安装即可使用。()

2.默认情况下,Flask-WTF为每个表单启用CSRF保护。()

3.Flask中定义的类视图需要重写dispatch_request()方法。()

4.Flask程序使用表单时需要设置密钥。()

5.WTForms是一个使用灵活的表单验证和渲染库,可以与Flask,Django等多个web框架结合使用。()

三,选择题

1.下列选项中,标识复选框的字段类是()。

A.DataField

B.BooleanField

C.DataTimeField

D.FileField

2.下列选项中,关于Flask-WTF的描述说法错误的是()。

A.Flask-WTF通过Python代码创建表单

B.Flask-WTF支持表单数据验证,CSRF保护等功能

C.虚拟环境中无法使用Flask-WTF扩展包

D.在安装Flask-WTF扩展包时会将WTForms一同安装

3.下列选项中,用于验证两个字段值是否相等的验证器是()。

A.DataRequired

B.Email

C.EqualTo

D.Length

4.下列选项中,关于类视图的描述说法错误的是()。

A.类视图中可以使用类属性methods设置请求方式

B.类视图定义完成之后就可以处理接收的请求

C.基于方法的类视图中,通过定义与请求方式同名的类方法处理请求

D.使用add_url_rule()方法可以将类视图与URL进行映射

5.下列选项中,关于蓝图的描述说法错误的是()。

A.通过蓝图可以将Flask程序分解成不同模块

B.使用Blueprint类可以创建蓝图对象

C.蓝图创建成功后,需要注册到Flask程序中

D.蓝图中不能定义路由

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/678311.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于vue+node.js的校园跳蚤市场系统多商家

校园跳蚤市场系统可以在短时间内完成大量的数据处理、帮助用户快速的查找校园跳蚤市场相关信息&#xff0c;实现的效益更加直观。校园跳蚤市场系统中采用nodejs技术和mysql数据库。主要包括管理员、发布者和用户三大部分&#xff0c;主要功能是实现对个人中心、用户管理、发布者…

CSS3弹性布局

传统的布局,基于盒状模型&#xff0c;依赖 display 属性 position属性 float属性。它对于那些特殊布局实现起来比较麻烦&#xff0c;就比如垂直居中&#xff0c;伸缩等。实现起来就不是很容易。 弹性布局是CSS3一种新的布局模式&#xff0c;是一种当页面需要适应不同的屏幕大…

uv机器电机方向极性

爱普生主板设置X、Y 电机方向极性&#xff1a;请根据实际情况设置&#xff0c;开机初始化时如果电机运动方向反了则修改此极性。 理光主板设置X、Y 电机方向极性

网课:[NOIP2017]奶酪——牛客(疑问)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 现有一块大奶酪&#xff0c;它的高度为 h&#xff0c;它的长度和宽度我们可以认为是无限大的&#xff0c;奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系&a…

Leecode之反转链表

一.题目及剖析 https://leetcode.cn/problems/reverse-linked-list/description/ 二.思路引入 设定三个指针,n1指向空, n2指向head,n3指向下一个元素,将n2->next指向n1,然后三个指针向后遍历重复即可 三.代码引入 /*** Definition for singly-linked list.* struct List…

[论文总结] 深度学习在农业领域应用论文笔记12

文章目录 1. 3D-ZeF: A 3D Zebrafish Tracking Benchmark Dataset (CVPR, 2020)摘要背景相关研究所提出的数据集方法和结果个人总结 2. Automated flower classification over a large number of classes (Computer Vision, Graphics & Image Processing, 2008)摘要背景分割…

开源版发卡小程序源码,云盘发卡微信小程序源码带PC端

一款发卡小程序。带PC端 系统微信小程序前端采用nuiapp 后端采用think PHP6 PC前端采用vue开发 使用HBuilderX工具打开&#xff0c;运行到微信小程序工具&#xff0c;系统会自动打包微信小程序代码 修改文件common/request/request.js 改成你的后端网址 微信小程序端完全…

python coding with ChatGPT 打卡第19天| 二叉树:合并二叉树

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

ChatGPT高效提问—prompt常见用法(续篇十)

ChatGPT高效提问—prompt常见用法(续篇十) 1.1 使用引导词 ​ 除了利用prompt引导ChatGPT回答问题,另一种重要的应用场景是让ChatGPT根据需求生成各种内容,比如诗词创作、故事续写、招聘信息编写,甚至是舞台剧剧本创作等。在这些场景中,我们可以采取一个巧妙的策略,那…

SpringCloud-Nacos服务分级存储模型

Nacos 服务分级存储模型是 Nacos 存储服务注册信息和配置信息的核心模型之一。它通过将服务和配置信息按照不同级别进行存储&#xff0c;实现了信息的灵活管理和快速检索&#xff0c;为微服务架构下的服务发现和配置管理提供了高效、可靠的支持。本文将对 Nacos 服务分级存储模…

CVE-2021-44915 漏洞复现

CVE-2021-44915 路由/admin/admin.php是后台&#xff0c;登录账号和密码默认是admin、tao&#xff0c;选择管理栏目菜单。 点击编辑&#xff0c;然后随便改点内容&#xff0c;提交时候抓包。 id是注入点。直接拿sqlmap跑就行了。

FPGA_工程_基于rom的vga显示

一 框图 二 代码修改 module Display #(parameter H_DISP 1280,parameter V_DISP 1024,parameter H_lcd 12d150,parameter V_lcd 12d150,parameter LCD_SIZE 15d10_000 ) ( input wire clk, input wire rst_n, input wire [11:0] lcd_xpos, //lcd horizontal coo…

Redis核心技术与实战【学习笔记】 - 26.Redis数分布优化(应对数据倾斜问题)

简述 在切片集群中&#xff0c;数据会按照一定的规则分散到不同的实例上保存。比如&#xff0c;Redis Cluster 或 Codis 会先按照 CRC 算法的计算值对 Slot&#xff08;逻辑槽&#xff09;取模&#xff0c;同时 Slot 又有运维管理员分配到不同的实例上。这样&#xff0c;数据就…

【芯片设计- RTL 数字逻辑设计入门 番外篇 9 -- SOC 中PL端与PS端详细介绍】

文章目录 Programmable Logic and Processing SystemPL&#xff08;Programmable Logic&#xff09;特点PS和PL之间的协同设计和开发工具 Programmable Logic and Processing System 在系统级芯片&#xff08;SoC&#xff09;的上下文中&#xff0c;“PL” 通常指的是可编程逻…

test fuzz-04-模糊测试 jazzer Coverage-guided, in-process fuzzing for the JVM

拓展阅读 开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) 开源 Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) test fuzz-01-模糊测试&#xff08;Fuzz Testing&#xff09; test fuzz-…

自动化AD域枚举和漏洞检测脚本

linWinPwn 是一个 bash 脚本&#xff0c;可自动执行许多 Active Directory 枚举和漏洞检查。该脚本基于很多现有工具实现其功能&#xff0c;其中包括&#xff1a;impacket、bloodhound、netexec、enum4linux-ng、ldapdomaindump、lsassy、smbmap、kerbrute、adidnsdump、certip…

YOLO系列详解(YOLOV1-YOLOV3)

YOLO算法 简介 本文主要介绍YOLO算法&#xff0c;包括YOLOv1、YOLOv2/YOLO9000和YOLOv3。YOLO算法作为one-stage目标检测算法最典型的代表&#xff0c;其基于深度神经网络进行对象的识别和定位&#xff0c;运行速度很快&#xff0c;可以用于实时系统。了解YOLO是对目标检测算…

【leetcode热题100】子集 II

给你一个整数数组 nums &#xff0c;其中可能包含重复元素&#xff0c;请你返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。返回的解集中&#xff0c;子集可以按 任意顺序 排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,2] 输出…

C++初阶:适合新手的手撕vector(模拟实现vector)

上次讲了常用的接口&#xff1a;C初阶&#xff1a;容器&#xff08;Containers&#xff09;vector常用接口详解 今天就来进行模拟实现啦 文章目录 1.基本结构与文件规划2.空参构造函数&#xff08;constructor)4.基本函数&#xff08;size(),capacity(),resize(),reserve())4.增…

算法学习——LeetCode力扣栈与队列篇1

算法学习——LeetCode力扣栈与队列篇1 232. 用栈实现队列 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 描述 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQu…