“老项,大问题,大问题。我做了一些前端页面,里面还有一些css,js,图片这样的静态文件,可以在flask应该如何引用这些文件呢?还有一个问题,我的前端里面有一些post提交的数据,比如图片上传或者表单提交,但是我不会啊!”小王刚到公司,看到老项就焦急的说。
“那你别着急了,赶巧了,我今天正好要给你讲静态文件的处理,post和表单这几个内容。赶紧过来吧,咱们开始上课了。”老项说完,开始了今天的讲解。
静态文件和页内url的处理
在网站的前端部分,除了html文件外,还有很多其它的文件,比较css,js,字体,图片资源等文件。html会引用这些文件,为了让html可以更好的访问到这些文件,我们首先会把文件放在static文件夹下,然后按如下图代码书写路径即可。
我们把一张图片放到了static文件夹下面img文件夹下,然后在模板代码中使用第15行的方式引用图片即可。显示效果如下:
当然这种硬编码的方式并不灵活,不建议使用,更好的办法是使用url_for方法通过路由找到图片。代码见下图。
注意第15行代码,我们在模板中直接使用了url_for方法,第一个参数写静态文件夹的目录名称‘static’,第二个参数写static文件夹内具体的文件路径。运行的效果和前面的一致。
“既然静态文件可以通过url_for找到,那我站内的一些url跳转,是不是也可以这么做?”聪明的小王想到了一个关键问题,问道。
“当然可以的,比如有主页里面有一些链接,可以跳转到某个品牌的详情页,我们把前面路由,视图,模板和数据库的内容结合一下,前后台代码可以这样写。”老项回答完,敲起了代码,代码如下图。
第一个截图是后台实现的两个视图,分别是首页和品牌详情页的视图,具体的代码大家可以根据前面所学内容进行理解。第二个截图是首页模板,注意看第六行代码,里面的a标签的href使用了url_for来生成链接地址。注意要写参数,具体参数的含义请结合视图层代码进行理解。第三个截图是一个简单的品牌详情页。代码运行后的两个页面截图如下。
点击链接以后,跳转到如下页面
“小王,明白怎么解决静态文件和url链接问题了吧?其它静态文件引用的路径参考这个写就行了。接下来我们说一下post的问题。”老王说完,又开始了讲解。
post和表单的处理
我们前面的例子基本都是get请求的案例,就是浏览器发送一个get请求,服务器返回一个响应,浏览器对页面进行显示。但有的时候,我们还要给服务器发送一些数据,这个时候就需要用到post请求了。
我们还是以小王的项目为例,假设现在需要增加一个功能,需要在首页增加一个输入框,输入品牌名称,点击输入框旁边的搜索按钮,将品牌信息发送给后台进行搜索,然后后台将搜索结果通过响应发送给浏览器进行显示。前后台代码分别如下图所示。
我们先看前端代码,注意看第一个截图的第8行到第11行代码,我们定义了一个表单,在表单里面有一个输入框和一个查询按钮。表单的action用于指定表单数据提交的url,我们还是让数据提交到主页处理视图,后面method指定提交的方法为post,也就是把输入框的数据提交到后台。
我们再看后台的代码,在第7行代码我们的路由装饰器里面,新增了一个参数methods,该参数用于指定装饰视图方法可以处理的http请求,如果不加该参数,默认只能处理get请求。代码中可以处理get和post请求。
代码的第9行用于判断当前的请求类型,其中request在第1行进行了导入。如果request.method是get方法,那么就进行第10行和第11行的处理,也就是查询所有的品牌并进行渲染返回。
如果request.method是post方法,就会找到request里面form的参数,通过form.get()方法获取post的数据,也就是输入框中用户输入的品牌,注意该方法的参数和前端代码第9行中的name参数一致,也就是carbrand。获取到用户输入的数据后,在车辆品牌表中使用name字段对该数据进行过滤查询。还是将数据渲染到前端页面进行显示。最终执行的效果如下图。
当然,在post处理中,也可以结合url_for和redirect跳转到另一个视图进行处理。我们除了可以直接这样处理表单提交的post请求,也可以使用flask的扩展包Flask-WTF来处理表单。下面进行介绍。
使用Flask-WTF处理表单
- Flask-WTF的安装和基本配置
要使用Flask-WTF前首先要进行安装。直接在虚拟环境下使用pip install flask-wtf进行安装,也可以在pycharm中进行安装。安装完成后如果需要启用跨站请求攻击保护,就需要配置一个SECRET_KEY用来建立加密令牌,可以尽可能复杂一点,并把CSRF_ENABLED设置为True,配置代码见下图。
- 使用Flask-WTF
我们还是以小王的项目为例,假设要实现一个可以手动录入车辆品牌信息的功能。这个功能页面应该有一个表单,表单内有一些输入框可以录入品牌名称,品牌介绍等信息,还应该有一个提交按钮。我们就利用Flask-WTF来构建表单模型。app.py里面新增如下图代码。
后端代码的第12行到第15行定义了一个表单类,该表单类继承自FlaskForm(见第3行的导入代码)。
表单类里面定义了三个类属性,这三个类属性分别是类StringField和SubmitField(这两个类在第4行导入)的实例,它们实例化的第一个参数对应html的label属性,注意brand_name的第二个参数validators指定了一个由验证函数构成的列表,可以对输入的值进行验证,DataRequired()方法要求这个字段必须要有输入值,不然就是无效的输入。这三个类属性分别是表单的品牌名称字段,品牌介绍字段和提交按钮。
后端代码18行到30行定义了car_search页面的视图方法。因为要在页面上显示表单,第20行代码实例化了我们定义的表单类,如果是get请求,直接将表单渲染到页面上即可。如果是post请求,则说明表单有数据提交,此时首先判断提交的数据是否有效(第24行),然后直接从form表单中获取品牌名称和品牌介绍(第25行和第26行),注意从表单实例获取数据的写法。27到29行代码将提交的数据存储到数据库,最终在页面上渲染表单以及提交成功的提示。
该视图对应的前端代码如下(新建了一个car_search.html文件)。
前端代码中,在form表单中书写我们的表单数据,第6行使用了form类的hidden_tag 方法,该方法渲染隐藏的字段,包括csrf字段。第7行和第8行显示表单的label标签和表单的输入框,第9行显示提交按钮。第11行用于提示表单提交的状态。这几行代码均是通过后台提交的数据进行渲染,生成了在前台显示的表单页面。代码运行的截图如下。
提交成功后,数据库增加了新的数据。
在表单处理中,处理案例中的两种字段,还有更多类型的字段,请见下表。
字段类型 | 说明 |
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenFiel | 隐藏字段 |
DateField | 日期字段 |
DateTimeField | 日期时间字段 |
IntegerField | 整数字段 |
DecimalField | 小数字段 |
FloatField | 浮点数字段 |
BooleanField | 复选框 |
RadioField | 单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 可以选多个值的下拉列表 |
FileField | 文件字段 |
SubmitField | 提交按钮 |
FormField | 表单嵌入另一个表单 |
FieldList | 一组指定类型的字段 |
大家在实际操作的时候,根据自己表单的实际需要选用合适的字段类型即可。除了字段外,wtf也提供了一些内建的验证函数,如下表所示。
函数名称 | 函数说明 |
| 验证电子邮件地址 |
EqualTo | 比较两个字段的值,如密码确认 |
IPAddress | 验证 IPv4 网络地址 |
Length | 验证输入字符串的长度 |
NumberRange | 验证输入的值在数字范围内 |
Optional | 无输入值时跳过其他验证函数 |
Required | 确保字段中有数据 |
Regexp | 使用正则表达式验证输入值 |
URL | 验证 URL |
AnyOf | 确保输入值在可选值列表中 |
NoneOf | 确保输入值不在可选值列表中 |
“关于表单的处理就先讲到这,小王,你今天回去的任务就是把静态文件处理好,url处理好,把你这个项目的post请求和表单处理好。”老项讲完,给小王布置了今天的任务。这时候,也上班了,他俩就各自回工作岗位工作去了。
本章任务:
1 处理好项目中的静态文件
2 处理好页面内部的url跳转
3 练习表单的使用和post请求的处理