zoukankan      html  css  js  c++  java
  • python flask学习(3)

    这次主要学习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 %}

    <form method="POST" action="/post-url/">
        {% csrf_token %}
         
        <input name='alex' value="xxx">
    </form>

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

    flaskCSRF防护设置方式

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

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

    2.表单类

    index.html文件:

    <html>
        <head>
            <title>首页</title>
        </head>
        <body>
            {% if name %}
                <h1>Hello,{{ name }}!</h1>
            {% else %}
                <h1>Hello Stranger!</h1>
            {% endif %}
    
            <form method="POST">
                {{ form.hidden_tag() }}
                {{ form.name.label  }} {{ form.name() }}
                {{ form.submit() }}
            </form>
        </body>
    </html>

    app.py 文件:

    from flask import Flask,render_template
    from flask.ext.wtf import Form
    from flask.ext.bootstrap import Bootstrap
    from wtforms import StringField,SubmitField
    from wtforms.validators import Required
    
    class NameForm(Form):
        name = StringField('你的名字?',validators=[Required()])
        submit = SubmitField('提交')
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'ni cai'
    bootstrap = Bootstrap(app)
    
    @app.route('/',methods=['GET','POST'])
    def index():
        name = None
        nameForm = NameForm()
    
        if nameForm.validate_on_submit():
            name = nameForm.name.data
            nameForm.name.data = ''
        
        return render_template('index.html',form=nameForm,name=name)
    
    if __name__ == '__main__':
        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文件:

    {% extends "base.html" %}
    {% import "bootstrap/wtf.html" as wtf %}
    
    
    {% block title %}首页 {% endblock %}
    
    {% block page_content %}
    
    <div class="page-header">
    {% if name %}
    <h1> Hello,{{ name }}! </h1>
    {% else %}
    <h1>Hello,Stranger!</h1>
    {% endif %}
    </div>
    
    {{ wtf.quick_form(form) }}
    
    {% endblock %}

    注意:

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

    重定向和用户会话

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

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

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

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

    from flask import Flask,render_template,session,url_for,redirect
    from flask.ext.wtf import Form
    from flask.ext.bootstrap import Bootstrap
    from wtforms import StringField,SubmitField
    from wtforms.validators import Required
    
    class NameForm(Form):
        name = StringField('你的名字?',validators=[Required()])
        submit = SubmitField('提交')
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'ni cai'
    bootstrap = Bootstrap(app)
    
    @app.route('/',methods=['GET','POST'])
    def index():
        name = None
        nameForm = NameForm()
    
        if nameForm.validate_on_submit():
            session['name'] = nameForm.name.data
            nameForm.name.data = ''
            return redirect(url_for('index'))
        
        return render_template('index.html',form=nameForm,name=session.get('name'))
    
    if __name__ == '__main__':
        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

    from flask import Flask,render_template,session,url_for,redirect,flash
    from flask.ext.wtf import Form
    from flask.ext.bootstrap import Bootstrap
    from wtforms import StringField,SubmitField
    from wtforms.validators import Required
    
    class NameForm(Form):
        name = StringField('你的名字?',validators=[Required()])
        submit = SubmitField('提交')
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'ni cai'
    bootstrap = Bootstrap(app)
    
    @app.route('/',methods=['GET','POST'])
    def index():
        name = None
        nameForm = NameForm()
    
        if nameForm.validate_on_submit():
            newName = nameForm.name.data
    
            if newName == session.get('name'):
                session['name'] = nameForm.name.data
                nameForm.name.data = ''
                return redirect(url_for('index'))
            else:
                flash('名字输入错误!')
                
        
        return render_template('index.html',form=nameForm,name=session.get('name'))
    
    if __name__ == '__main__':
        app.run(debug=True)

    base.html 文件

    {% extends "bootstrap/base.html" %}
    
    {% block title %}Flasky {% endblock %}
    
    {% block navbar %}
    <div class="navbar navbar-inverse" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">Flasky</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="/">Home</a></li>
                </ul>
            </div>
        </div>
    </div>
    {% endblock %}
    
    {% block content %}
    
    <div class="container">
    {% for message in get_flashed_messages() %}
    <div class="alert alert-warning">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    {{ message }}
    </div>
    {% endfor %}
    
    {% block page_content %}{% endblock %}
    </div>
    
    {% endblock %}

    注意:

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

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

  • 相关阅读:
    HDU 1160 dp中的路径问题
    zzuli 1907: 小火山的宝藏收益
    POJ 3414 dfs广搜直接应用
    http://acm.zzuli.edu.cn/zzuliacm/problem.php?cid=1158&pid=5 二分函数的间接应用
    LightOJ 1067 组合数取模
    九段美到极致的句子
    质数和分解
    codevs 1080 线段树练习
    codevs 2806 红与黑
    codevs 2152 滑雪
  • 原文地址:https://www.cnblogs.com/dion-90/p/8338439.html
Copyright © 2011-2022 走看看