表单

表单是实现一个web程序非常重要的部分,依我之见,表单是整个应用系统的数据输入部分,不仅在整个程序的正常运行中起着非常大的作用,还深刻影响到整个应用系统的稳定性和性能,也是系统安全比较关心的一个部分。在此书中使用的是基于WTForms拓展的Flask-WTF,这个拓展不仅能在后端清晰地声明好表单的形式,还可以便捷的实现表单的验证,结合jinja渲染系统,还可以实现其在前端的表现。我在深入阅读中发现,定义好的扩展可以在后端程序和渲染时分别设置其html标签的属性,这样一来,一方面可以结合Bootstrap之类的ui框架,通过class属性设置其外观,另一方面在后端定义可以方便的实现复用属性部分的编写,前端设置可以实现不同页面的个性化需求。

具体用法,首先需要在表单模块中从flask-form导入FlaskForm作为后续表单类的父类,然后再从wtforms中导入需要使用到的表单类型和验证器,然后定义表单即可。其中验证器一般是html自身可以实现的简单表单验证,例如长度限制,数字范围、网址邮箱电话等,也有非常实用的html似乎无法直接实现的如正则表达式,限定值等等使用功能。需要注意的是,虽然在导入时验证器是以类的形式导入的,但在使用时需要加上括号,标识其为可调用对象。一个例子:

from flask_wtf import FlaskForm
from wtforms import SubmitField, StringField, TextAreaField
from wtforms.validators import DataRequired, Lengthclass MessageForm(FlaskForm):title = StringField('title',validators=[DataRequired(), Length(1, 50)], # 需要打括号 必要时传入参数render_kw={'placeholder': 'Message title / 标题'})body = TextAreaField('message', validators=[DataRequired(), Length(1, 140)])submit = SubmitField()

对于前端显示的html代码,可以通过前面说的两种方式传入属性。第一种方式就是如上面的代码显示的,在后端定义时,在对应的条目建立时,传入一个render_kw的键值对形式的参数。另一种方法就是在jinja模板中,如下书写:

<div class="col-lg-6 mb-4">{{ form.title(class_='form-control') }}
</div>

需要注意的是,表单类并不作为程序运行的上下文供模板调用,需要实例化后传入模板。在模板中使用时,如果要设置html标签的class属性,需要在后面加一个下划线,与python的class关键字有所区别。那么自定义验证器输出后是否可以在前端实现?(我猜自定义的可能不行,涉及到JavaScript的部分还是需要自己写)html自身不能实现的部分前端验证是什么原理?前端使用JavaScript写的一些规则是否仍然有效?

然而,WTForms做的仅仅是服务端的验证,稍微复杂一点的验证器需还是要是通过自己在前端手写JavaScript代码实现,所以以上的的问题很多都是根本不存在的。这个拓展在jinja模板中输出了html代码后,在上传视图函数接收前就不管了,前端依然是正常的处理,JavaScript也依然可以起作用。

后端又是如何处理呢?WTForms需要将用户上传的信息先储存在一个实例化的表单对象中,然后通过调用这个对象的validate()方法验证信息。通过验证后,进行处理(计算、调用数据库等),最后给客户端重定向一个GET请求,并给予用户适当的提示。在这个过程中,FlaskForm基类会自动从上下文中获取请求中的表单信息,无需手动执行。需要注意的是,向数据库内写入数据时,需要调用字段的data属性,而不是将整个表单的字段类写入。

关于CSRF

在这个扩展中,提到了很多关于防御CSRF攻击的事情。CSRF是Cross-site request forgery,跨站伪造请求攻击。它相比于XSS攻击来说,需要更严格的条件,因此在防御上也更有难度。当用户A与访问被攻击网站B,还存在一个恶意网站C,一般来说,进行CSRF攻击需要用户已经登陆了网站B,并且没有关闭网站B的页面(session有效)。在这个条件下,用户A访问网站C,触发C以用户A的身份请求对网站B进行操作,从而实现攻击,而请求网站B这个操作是A不知情的。这个攻击过程,需要注意,网站C并没有窃取任何用户A的信息,只是通过用户A的浏览器,在A不知情的情况下向B发送了攻击请求。

防御手段之一就是检查请求头的reference,如果不是来自于站内或者是指定的URL,就拒绝请求。然而这是不靠谱的,请求头很容易被篡改。在WTForms中,是使用csrf-token来防御的,在表单中添加一段随机的、加密的、有时效的token字符串字段,这也是一个非常常用的方法。在学习时看见有评论在提问,既然攻击者能伪造用户身份,你一条字符串怎么就不能伪造?首先,字符串不仅仅是随机的,更是被加密的,需要有服务端密钥才能正确伪造;其次,攻击者是通过浏览器发送请求,伪造用户身份,身份数据保存在浏览器cookies与session中,攻击对象是客户端,即使用户现在打开了一个有csrf-token的页面,他没办法从另一个页面中获取这个数据。还有一种方式是验证码,这种方式不仅可以防御CSRF攻击,还可以减少网络爬虫对服务端的骚扰。

蓝本与模块化

蓝本

当我第一次在flask中看到蓝本这个名词的的时候,我内心里马上浮现出一种“宏伟蓝图”的形象,以为这是一个了不得部分,他是不是可以提供各种有力的扩展,帮我搞定各种难题?随着我深入的学习,我发现我想错了。蓝本只是将原来app.py中的视图函数单独拿出来,根据功能或者域名,将视图函数们模块化与主程序分离。只不过视图函数是整个web程序中比较重要的一部分,牵涉到环境、路由和资源加载等一系列问题,值得单独拿出来研究。

蓝本的的引入,就不得不深入理解一下前面提到的关于url、端点和视图函数之间的关系。这三层之间,结合前面的路由表,可以看出,其实是一个两层映射的关系。url规则和端点的映射,端点和视图函数的映射。多个url可以对应到一个端点上,例如/ /home /index三条url都可以绑定到首页的端点上。那为什么不直接对应到视图函数的函数名名上呢,需要中间进行一层端点的映射?蓝图的出现可以解决这个问题,通过端点的引入,可以为每个蓝图内部创建本地的命名空间。比如一个CMS系统,用户访问的网址首页是www.websit.com/index,后台管理的网址首页是admin.websit.com/index,在url规则看来,他们都是/index,但是他们的前缀有所不同(通过注册蓝图时的subdomain参数实现),为了能对应到不同蓝本的同名视图函数上,需要使用带前缀的端点,类似于类的调用:admin.index pub.index

模块化

之前在数据库部分讨论过,flask的app实例需要创建后才能继续加载其他的拓展,这给不同拓展的相关代码的模块化处理带来了不便。作者当时的解决方法是先将app实例化,拓展对象也实例化完成后,通过函数传参的方式传递到拓展代码中,实现模块化。然而这种方法不仅代码冗余,逻辑上也不容易理解,虽然实现了模块化,但单独的拓展模块代码的代码可读性非常低(拓展和app在代码中只是参数名,没有上下文供理解)

事实上有更优的解决方案,flask及其拓展开发者们早就考虑到了这个问题,大部分flask相关拓展都可以在没有app实例的情况下先行定义,然后再在创建程序实例时使用object.init_app(app)方法将拓展初始化。这种做法不仅实现了代码层面的模块化,更是架构上的模块化,flask实例不用写死在程序中,可以在主程序的__init__.py文件中组织工厂函数(面向对象编程中创建对象实例的函数)

回到上面关于蓝本的讨论,蓝本使得冗长的视图函数代码可以模块化组织。开发者可以通过业务的实际需求将所有的函数进一步模块化,一套程序多个蓝本,将不同的程序功能分开,便于开发、维护。除了数据库模型和蓝本外,表单模型,模板渲染模型(本项目为Bootstrap)也可以模块化处理。

Flask web 表单、蓝本与代码模块化相关推荐

  1. Flask Web表单

    title: flask学习笔记 subtitle: 3. flask Web表单 date: 2018-12-14 10:17:28 --- Web表单 HTML表单是用户和web站点或应用程序之间 ...

  2. Flask开发系列之Web表单

    Flask开发系列之Web表单 简单示例 from flask import Flask, request, render_templateapp = Flask(__name__) @app.rou ...

  3. Flask之Web表单使用

    Web表单使用 @(Flask) request对象包含客户端发出的所有请求信息. request.form能获取POST请求中提交的表单数据. 使用的包 Flask-WTF可以把处理Web表单的过程 ...

  4. Flask实践——microblog WEB表单 (3)

    WEB表单 配置 创建microblog/config.py CSRF_ENABLED = True SECRET_KEY = 'you-will-never-guess' 修改app/__init_ ...

  5. Python Flask学习_使用Flask-wtf和web表单

    HTML中的<form> 元素表示表单,表单用于收集用户输入. 之前,学习使用request.form获取表单数据.但是有些任务重复单调,可以实现自动化管理,比如 :生成表单的HTML代码 ...

  6. 第四章 WEB表单(二)

    一. 重定向和用户会话 WEB表单(一)最后部分,当我们提交表单后,点击浏览器的刷新按钮时,看到一个警告"再次提交表单之前进行确认".这是因为刷新浏览器时会重新发送之前发送过的请求 ...

  7. python-flask(二)集成bootstrap、集成web表单、集成邮件发送

    文章目录 一.flask集成bootstrap 1. 什么是Bootstrap? 2. Flask中如何集成Bootstrap? 3. Flask-Bootstrap实现了什么? 二.Flask中集成 ...

  8. Study_microblog笔记Part 3--web表单

    本部分学习如何使用表单为用户发表动态和登录认证提供途径.处理web表单使用flask-wtf插件. 1.安装flask-wtf. (microblog) D:\pythonProgram\Pychar ...

  9. 使用Vue动态生成form表单的实例代码

    具有数据收集.校验和提交功能的表单生成器,包含复选框.单选框.输入框.下拉选择框等元素以及,省市区三级联动,时间选择,日期选择,颜色选择,文件/图片上传功能,支持事件扩展. 欢迎大家star学习交流: ...

  10. 使用 PEAR的Text_CAPTCHA保护Web表单[翻译]

    使用 PEAR的Text_CAPTCHA保护Web表单 作者 Marcus Whitney 翻译 mikespook 来源 http://phpsec.org 当你在网络上有公开的表单的时候,你总是需 ...

最新文章

  1. glove 安装错误
  2. 商汤联手华科:提出文字检测模型GNNets,新颖模块可解决几何分布难题
  3. C语言----表达式求值之隐式类型转换
  4. Lambda方法推导(method references)
  5. CentOS屏幕录制
  6. mysql 加号的作用_MySQL学习笔记(一)
  7. html移动端怎么做城市选择,移动端页面单位的选择(px, em, rem, vw)
  8. [转]布隆过滤器详解
  9. python每日经典算法题5(基础题)+1(较难题)
  10. 显示桌面图标不见了的解决方法
  11. 单片机原理及应用(c51语言版)(一)
  12. 浪潮ERP-PS异速联远程接入解决方案
  13. java入门-dos窗口的用法
  14. 智能辅助系统在配电站所内的建设及应用
  15. 植物大战僵尸修改植物攻击力
  16. VScode淡绿色护眼设置
  17. 文科生学python简书_文科生Python教程(一)
  18. 格力2代,原厂固件hola1.2.2
  19. 采用FFmpeg从视频中提取音频(声音)保存为mp3文件
  20. Niagara模块微信公众号连接

热门文章

  1. 大道至简——软件工程实践者的思想知识导图
  2. Java字符串基础语法
  3. 利用java打印心型图案
  4. android—AOSP、AOKP、CM的区别
  5. 保研分享:双非软件学渣 - 985CS
  6. 2db多少功率_db与w换算(1db等于多少功率)
  7. exchange服务器维护,Exchange服务器之禁用和删除Exchange邮箱深入探讨
  8. plsql 快捷键 设置 字母大小写
  9. Windows2016 主从CA(一、企业根CA与独立从CA)
  10. 为了自己的梦想而努力