这次主要学习web表单。学了下,很像是Django的form表单验证。不过有许多的不同。可以说是功能更加碎块化。Django的验证方式是很固定和严谨的,风格完全不同。

尽管Flask的请求对象提供的对象足够用于处理Web表单(如:request.form能获取POST请求中提交的表单数据),但有些任务很单调,而且要重复操作。比如生成表单的HTML代码和验证提交的表单数据。

Flask-WTF(http://pythonhosted.org/Flask-WTF)扩展可以把处理Web表单的过程编程一种愉快的体验。这个扩展对独立的WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到Flask程序中。

1.跨站请求伪造保护

默认情况下,Flask-WTF能保护所有表单面免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站是就会引发CSRF攻击。

为了实现CSRF保护,Flask-WTF需要程序设置一个密钥。Flask-WTF使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。

这里也像是Django的CSRF防护。不过Django中是在POST表单提交中加入 {% csrf_token %}

  1. <form method="POST" action="/post-url/">
  2. {% csrf_token %}
  3.  
  4. <input name='alex' value="xxx">
  5. </form>

还有其ajax调用方式。不过这里不赘述。

flaskCSRF防护设置方式

  1. app = Flask(__name__)
  2. app.config['SECRET_KEY'] = '这里设置密钥'

注意:为了增强安全性,密钥不应该直接写入代码,而要保存在环境变量中。

2.表单类

index.html文件:

  1. <html>
  2. <head>
  3. <title>首页</title>
  4. </head>
  5. <body>
  6. {% if name %}
  7. <h1>Hello,{{ name }}!</h1>
  8. {% else %}
  9. <h1>Hello Stranger!</h1>
  10. {% endif %}
  11.  
  12. <form method="POST">
  13. {{ form.hidden_tag() }}
  14. {{ form.name.label }} {{ form.name() }}
  15. {{ form.submit() }}
  16. </form>
  17. </body>
  18. </html>

app.py 文件:

  1. from flask import Flask,render_template
  2. from flask.ext.wtf import Form
  3. from flask.ext.bootstrap import Bootstrap
  4. from wtforms import StringField,SubmitField
  5. from wtforms.validators import Required
  6.  
  7. class NameForm(Form):
  8. name = StringField('你的名字?',validators=[Required()])
  9. submit = SubmitField('提交')
  10.  
  11. app = Flask(__name__)
  12. app.config['SECRET_KEY'] = 'ni cai'
  13. bootstrap = Bootstrap(app)
  14.  
  15. @app.route('/',methods=['GET','POST'])
  16. def index():
  17. name = None
  18. nameForm = NameForm()
  19.  
  20. if nameForm.validate_on_submit():
  21. name = nameForm.name.data
  22. nameForm.name.data = ''
  23.  
  24. return render_template('index.html',form=nameForm,name=name)
  25.  
  26. if __name__ == '__main__':
  27. app.run(debug=True)

注意:

0.NameForm类,声明了一个输入姓名文本框和提交按钮。字段构造函数第一个参数吧表单渲染成HTML时使用的标号。其中输入姓名的文本框需要必须填写。

1.app.route修饰器中添加的methods参数告诉Flask在URL映射中把这个视图函数注册为GET和POST请求的处理程序,如果没有指定methods参数,就只把视图函数注册为GET请求处理程序。因为Web表单提交为POST方式,故需要显示标明。

2.nameForm.validate_on_submit()方法,提交表单后,如果数据被所有验证函数接受,那么nameForm.validate_on_submit()方法返回True,否则返回False。

index.html文件:

  1. {% extends "base.html" %}
  2. {% import "bootstrap/wtf.html" as wtf %}
  3.  
  4. {% block title %}首页 {% endblock %}
  5.  
  6. {% block page_content %}
  7.  
  8. <div class="page-header">
  9. {% if name %}
  10. <h1> Hello,{{ name }}! </h1>
  11. {% else %}
  12. <h1>Hello,Stranger!</h1>
  13. {% endif %}
  14. </div>
  15.  
  16. {{ wtf.quick_form(form) }}
  17.  
  18. {% endblock %}

注意:

1.wtf.quick_form()函数的参数为Flask-WTF表单对象,使用Bootstrap默认样式渲染传入的表单

重定向和用户会话

为何别让web程序把post请求作为浏览器发送的最后一个请求?

因用户在刷新页面后会再次提交表单,这样不仅用户体验下降,而且会加重服务器压力。解决办法是使用重定向作为POST请求的响应,而非常规响应。

但这种方法的问题是,程序处理完POST请求时,使用form.name.data获取用户提交的数据,可请求结束,数据丢失。用户登录信息应该要保存下来的,否则登陆的意义何在?

为了使请求记住数据,就需要用户会话了。用户会话是一种私有存储,存在于客户端的cookie中。这里我们用请求上下文中名为session的变量实现。

  1. from flask import Flask,render_template,session,url_for,redirect
  2. from flask.ext.wtf import Form
  3. from flask.ext.bootstrap import Bootstrap
  4. from wtforms import StringField,SubmitField
  5. from wtforms.validators import Required
  6.  
  7. class NameForm(Form):
  8. name = StringField('你的名字?',validators=[Required()])
  9. submit = SubmitField('提交')
  10.  
  11. app = Flask(__name__)
  12. app.config['SECRET_KEY'] = 'ni cai'
  13. bootstrap = Bootstrap(app)
  14.  
  15. @app.route('/',methods=['GET','POST'])
  16. def index():
  17. name = None
  18. nameForm = NameForm()
  19.  
  20. if nameForm.validate_on_submit():
  21. session['name'] = nameForm.name.data
  22. nameForm.name.data = ''
  23. return redirect(url_for('index'))
  24.  
  25. return render_template('index.html',form=nameForm,name=session.get('name'))
  26.  
  27. if __name__ == '__main__':
  28. app.run(debug=True)

注意:

1.这个新版中,name被保存在用户会话session['name']中。所以在多次请求中也能维持会话。存储类型是键值对形式

2.redirect()函数用于生成HTTP重定向,在redirect()函数中,参数是重定向的url,推荐用url_for()生成URL,该函数可以保证URP和定义的路由兼容

3.url_for()函数唯一需指定的参数是端点名。默认状况下,路由的端点是相应视图函数的名字。

4.render_templates()中,使用session.get()直接从会话中获取name参数的值。这里是直接使用get(0获取字典中键对应的值以避免异常情况。

flash消息

请求完成后,有时需要让用户知道状态发生了变化。

这种提示功能是Flask的核心特性,flash()函数可实现这种效果。

app.py

  1. from flask import Flask,render_template,session,url_for,redirect,flash
  2. from flask.ext.wtf import Form
  3. from flask.ext.bootstrap import Bootstrap
  4. from wtforms import StringField,SubmitField
  5. from wtforms.validators import Required
  6.  
  7. class NameForm(Form):
  8. name = StringField('你的名字?',validators=[Required()])
  9. submit = SubmitField('提交')
  10.  
  11. app = Flask(__name__)
  12. app.config['SECRET_KEY'] = 'ni cai'
  13. bootstrap = Bootstrap(app)
  14.  
  15. @app.route('/',methods=['GET','POST'])
  16. def index():
  17. name = None
  18. nameForm = NameForm()
  19.  
  20. if nameForm.validate_on_submit():
  21. newName = nameForm.name.data
  22.  
  23. if newName == session.get('name'):
  24. session['name'] = nameForm.name.data
  25. nameForm.name.data = ''
  26. return redirect(url_for('index'))
  27. else:
  28. flash('名字输入错误!')
  29.  
  30. return render_template('index.html',form=nameForm,name=session.get('name'))
  31.  
  32. if __name__ == '__main__':
  33. app.run(debug=True)

base.html 文件

  1. {% extends "bootstrap/base.html" %}
  2.  
  3. {% block title %}Flasky {% endblock %}
  4.  
  5. {% block navbar %}
  6. <div class="navbar navbar-inverse" role="navigation">
  7. <div class="container">
  8. <div class="navbar-header">
  9. <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
  10. <span class="sr-only">Toggle navigation</span>
  11. <span class="icon-bar"></span>
  12. <span class="icon-bar"></span>
  13. <span class="icon-bar"></span>
  14. </button>
  15. <a class="navbar-brand" href="/">Flasky</a>
  16. </div>
  17. <div class="navbar-collapse collapse">
  18. <ul class="nav navbar-nav">
  19. <li><a href="/">Home</a></li>
  20. </ul>
  21. </div>
  22. </div>
  23. </div>
  24. {% endblock %}
  25.  
  26. {% block content %}
  27.  
  28. <div class="container">
  29. {% for message in get_flashed_messages() %}
  30. <div class="alert alert-warning">
  31. <button type="button" class="close" data-dismiss="alert">&times;</button>
  32. {{ message }}
  33. </div>
  34. {% endfor %}
  35.  
  36. {% block page_content %}{% endblock %}
  37. </div>
  38.  
  39. {% endblock %}

注意:

1.flash()函数用于给client返回一个异常响应。当然,需要再前端基模板中渲染这些信息。前端可用get_flashed_message()函数获取并渲染消息。

2.这个例子中,使用了bootstrap提供的警报CSS样式渲染警告消息。

python flask学习(3)的更多相关文章

  1. Python Flask学习笔记之模板

    Python Flask学习笔记之模板 Jinja2模板引擎 默认情况下,Flask在程序文件夹中的templates子文件夹中寻找模板.Flask提供的render_template函数把Jinja ...

  2. Python Flask学习笔记之Hello World

    Python Flask学习笔记之Hello World 安装virtualenv,配置Flask开发环境 virtualenv 虚拟环境是Python解释器的一个私有副本,在这个环境中可以安装私有包 ...

  3. Python Flask学习

    开了一个新坑..一直以来对web的前端后端了解比较模糊,所以打算学一个后端框架,写个小博客什么的增长一下姿势水平. 初学嘛,选个相对轻量级一点的,就决定学习flask啦.

  4. python flask学习第2天 URL中两种方式传参

    新创建项目   自己写个url映射到自定义的视图函数 在url中传递参数 app.py from flask import Flask app = Flask(__name__) @app.route ...

  5. python flask学习(2)

    本文主要整理下几个Flask扩展: 0.Flask-Bootstrap:集成Twitter开发的一个开源框架Bootstrap.1.Flask-Script:为Flask程序添加一个命令行解析器2.F ...

  6. python flask学习(1)与Git基础操作

    今天从简单的flask开始完成Flask web开发的学习.今天学习了Git和GitHub项目的提交. Git尝试提交过程中出现了"Could not read from remote re ...

  7. Python Flask学习之安装SQL,python3,Pycharm(网上下载安装即可)

    1,下载时更改pypi源.可以额外安装虚拟化环境:pip install -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.co ...

  8. python flask学习第1天

    flask安装: 第一个flask程序: 用pycharm新建一个flask项目,新建项目的截图如下: app.py代码如下: #从flask这个包中导入Flask这个类 #Flask这个类是项目的核 ...

  9. Python Flask学习笔记(1)

    1.搭建虚拟环境 a. 安装 virtualenv : pip3 install virtualenv b. 建立虚拟环境 : 任意目录下建立一个空文件(我的是 Py_WorkSpace) ,在该文件 ...

随机推荐

  1. 五、hibernate在myeclipse中生成实体和映射

  2. Codeforces Round #408( Div2)

    Bank Hacking 阅读题,读完之后手算一下可以发现每一个bank被hack所需要的strength无非分为三种情况. 1. $a_i$,当且仅当i为第一个选择的点. 2. $a_i+1$,当且 ...

  3. Java的栈和堆

    JVM的内存区域可以被分为:线程栈,堆,静态方法区(实际上还有更多功能的区域,并且这里说的是JVM的内存区域) 线程栈:      注意这个栈和数据结构中的stack有相似之处,但并不是用户态的.准确 ...

  4. CF-798B

    B. Mike and strings time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  5. 5-1条件运算符 & 5-2

    三目运算符 新建类: ConditionDemo 用三目运算符: package com.imooc.operator; public class ConditionDemo { public sta ...

  6. 常用模块 re模块与正则表达式

    re模块 正则: 正则就是用一些具有特殊含义的符号组合到一起(称之为正则表达式)来描述字符或字符串的方法.或者说:正则就是用描述一类事物的规则.(在python中) 它内嵌在python中,并通过re ...

  7. 网络编程-http连接-GET&POST

    GetRequest package com.net.http; import java.io.BufferedReader; import java.io.IOException; import j ...

  8. 【WIP】Swift4 闭包

    创建: 2018/06/05 闭包的声明  闭包的概要 { (参数表) -> 型 in { ... } ● 参数不可以带默认值 ● 参数不可以带标签 ●  定义闭包并直接呼出必须要被代入 {re ...

  9. html实现点击图片放大功能

    话不多说,直接上代码 <html> <head> <style> .over {position: fixed; left:0; top:0; width:100% ...

  10. win7 mongod不是内部命令

    1.下载MongoDB 1.1 MongoDB下载 1.2 选择Server下面的 Community 2.安装MongoDB 2.1 注意事项:一直下一步就行了,但是遇到下面这个界面,注意一定要去掉 ...