Flask自带的常用组件介绍


Flask的优点是灵活小巧,三行代码即可运行一个web服务器,但基于Flask构建的功能并不比Django弱,关键就就是除了flask自带的基础功能外,还有丰富的组件进行支持,本文先对常用的自带组件进行简单的介绍。测试的Flask版本是0.12。

在构建Flask应用导入的时候,通常是from flask import Flask的方式开始的,说明flask这个python package里面应该还藏了不少好东西,从源码来看看:

from werkzeug.exceptions import abort
from werkzeug.utils import redirect
from jinja2 import Markup, escape

from .app import Flask, Request, Response
from .config import Config
from .helpers import url_for, flash, send_file, send_from_directory, \
    get_flashed_messages, get_template_attribute, make_response, safe_join, \
    stream_with_context
from .globals import current_app, g, request, session, _request_ctx_stack, \
    _app_ctx_stack
from .ctx import has_request_context, has_app_context, \
    after_this_request, copy_current_request_context
from .blueprints import Blueprint
from .templating import render_template, render_template_string

# the signals
from .signals import signals_available, template_rendered, request_started, \
    request_finished, got_request_exception, request_tearing_down, \
    appcontext_tearing_down, appcontext_pushed, \
    appcontext_popped, message_flashed, before_render_template

# We're not exposing the actual json module but a convenient wrapper around
# it.
from . import json

# This was the only thing that Flask used to export at one point and it had
# a more generic name.
jsonify = json.jsonify

# backwards compat, goes away in 1.0
from .sessions import SecureCookieSession as Session
json_available = True

Flask自带组件基本上都在这里了,我们一一来分析这些组件的功能及基本的用法。

Flask

Flask应用的主类,在源码分析中提到,不再赘述。这里给一个Flask应用的经典样例,请务必注意下面的代码都是在此样例基础上进行拓展的

#示例-1
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

render_template

def render_template(template_name_or_list, **context)

template_name_or_list参数是模板名称,context参数接受模板中已经定义的变量值。
Jinja是Flask的模板引擎,提供对HTML页面的数据渲染,render_template是Flask中调用template目录的html模板并渲染数据。代码示例:

#示例-2
from flask import render_template

@app.route("/")
def index():
    name="He Kejun"
    return render_template("index.html",name=name)

上述的代码中调用了/template/index.html模板,并将“name: He Kejun”这一数据渲染进该模板其可以直接通过Hello, {{name}}的方式显示‘Hello, He Kejun'

session

flask的session机制,Flask从服务器通过浏览器的cookie保存信息,该信息通过应用的秘钥进行加密确保数据安全。session在用户身份认证和数据共享提供较好的帮助。样例:

#示例-3
from flask import session
app.config["SECRET_KEY"]="YOU CAN NOT GUESS ME" #加密的秘钥,建议放在配置文件中

@app.route("/")
def index():
    session["name"]="kejun"
    return "hello,world"

@app.route("/name")
def name():
    return session["name"]

首先访问http://127.0.0.1:5000 生成用户名,查看浏览器的cookie可以看到session已经写入了,这时候再访问http://127.0.0.1:5000/name就可以看到名字了,在两个HTTP请求之间共享了{name: kejun}这个数据。

url_for

def url_for(endpoint, **values):

根据已经定义好的view函数来创建URL到指定的endpoint,Flask的endpoint可以理解为Restful框架中资源。输入的endpoint是函数名,values是关键字参数,每个关键字参数对应URL规则的变量部分,未知变量部分被插入到URL中作查询参数,具体的样例,我使用了官网的样例

#示例-4
from flask import url_for

@app.route("/")
def index(): pass

@app.route("/login")
def login(): pass


@app.route("/user/<username>")
def profile(username):pass

with app.test_request_context():
    print(url_for("index))  #/
    print(url_for("login"))  #/login
    print(url_for("login",next="/"))  #/login?next=/
    print(url_for("profile,username="kejun"))  @/user/kejun

redirect

def redirect(location, code=302, Response=None):

参数location是跳转的目标位置,code是HTTP响应码默认是302(临时移动),也可以设置为301(永久移动,即所请求的文档在别处),303(参见其他信息),305(使用代理),不可以是300(多重选择),304(未修正更新)。
redirect的作用是重定向,设置响应并跳转到指定的位置。在Flask中通常与url_for这个功能一起使用。应用实例:

#示例-5
from flask import redirect

@app.route("/")
@app.route("/index")
def index():
   return redirect(url_for("blog"))

@app.route("/blog")
def blog():  pass

在示例-5中,我们可以将一些用户可能会访问的链接重定向到博客主页上。

flash

def flash(message, category='message'):

参数message是消息内容,category是消息类型,方便前端过滤。
Web设计中提供用户的友好性是及时将反馈提供给用户。消息闪现Flash提供了一个非常简单的机制。

#示例-6-1
from flask import flash

def print_message():
    flash("This is a message","message")
    return "Message Page"

def print_error()
    flash("This is a error","error")
    return "Error Page"  

在前端,我们可以这样定义HTML页面从而显示内容

#示例-6-2
{% with msgs = get_flashed_messages(category_filter=["message"]) %}
    {% if msgs %}
        {% for msg in msgs %}
            <p>{{msg}}</p>
        {% endfor %}
    {% endif %}
{% endwith %}
{% with errors= get_flashed_messages(category_filter=["error"]) %}
    {% iferrors%}
         {% for errorinerrors%}
               <p>{{error}}</p>
         {% endfor %}
    {% endif %}
{% endwith %}

make_response

def make_response(*args):

Flask会自动将view函数返回的值转换成响应对象,除此之外,你可以通过调用make_response来生成可定制的响应对象,包括设置cookie,session等等,更多的使用方法可以参见教程

#示例-7
from flask import make_response

def index():
      return render_template('index.html', foo=42)

def index():
       response = make_response(render_template('index.html', foo=42))
       resp.set_cookie("am_i_handsome","yes") #设置cookie
       return response

在上述的示例中,通过make_response,还可以定制cookie。也就是说,通过make_response你可以个性化定制返回的响应对象。

jsonify

对于数据进行json转化,应用于通过ajax方式访问时需要返回json数据。

#示例-8
from flask importjsonify

@app.route("/update_user_name",methods=['GET', 'POST'])
def update_user_name():
    ip=request.headers.get('X-Real-Ip', request.remote_addr)
    user_name=request.args.get('new_user_name',"",type=str)
    if user_name:
        if set_user_name(ip,user_name):
            return jsonify(return_code="1")
    return jsonify(return_code="0")

blueprint

blueprint蓝图是flask自带的一种拓展已有应用结构的方式,这是Flask在中大型Web应用中的一种框架设计。蓝图把把功能类似或者同一模块下的视图函数组合在一起,基于蓝图,我们可以把Flask应用拆分成不同的组件。每个蓝图都可以自定义自己的模板文件目录和静态目录。定义好的蓝图目录可以通过注册的方式加入Flask应用中。代码示例如下:

#示例-9-1
from flask import Blueprint

example=Blueprint('example',__name__,template_folder='templates/example',static_folder='static/example',url_prefix='/example')

#蓝图example下的视图函数
@example.route
def index():
    return render_template("index.html")

一个蓝图就是一个模块,上述的example蓝图创建好后,需要注册到Flask应用中,样例代码如下:

示例-9-2
from flask import Flask
from yourapplication.examples import example

app = Flask(__name__)
app.register_blueprint(example)

本文之前介绍了url_for的使用方法,在蓝图中使用url_for定位视图函数需要增加蓝图名称,如定位到上述index视图函数url_for('example.index')

request

Flask构建了一个与请求相关的全局变量,在所有的视图函数及模板中都可以访问该对象。应用示例如下:

#示例-10
from flask import request
def get_user_ip():
    ip=request.headers.get('X-Real-Ip', request.remote_addr)
    return "Request ip address is {0}".format(ip)

abort

abort是Flask中Abort类的一个实例,通常采用abort(error_code)的方式进行调用。abort的状态码最好是自己实现的错误定义,如示例-11所示。

g

Flask中的全局变量g,可以为特定请求临时存储任何需要的数据并且是线程安全的,当请求结束时,这个对象会被销毁,下一个新的请求到来时又会产升一个新的g。

#示例-11
from flask import g,session,abort,render_template
@app.before_request
def before_request():
    if 'user_name' in session:
        g.user=User.query.get(session['user_name'])

@app.route('/admin')
def admin():
    if g.user is None:
        abort(404)
    return render_template('admin.html')

@app.errorhandler(404):
def page_not_found():
    return render_template("404.html"),404

send_from_directory

def send_from_directory(directory, filename, **options):

参数directory是文件所在目录,filename是文件名称,options参数是send_file的传入参数,options可选的参数包括 mimetype、as_attachment、attachment_filename、add_etags、cache_timeout、conditional。
send_from_directory可以认为send_file上加了一层壳子,判断了文件路径及文件名,然后交由send_file处理,实际上将文件内容发给浏览器,所以它一个重要的应用场景是支持文件下载。
对于文件下载,媒体数据流传输的可以再研究一下send_filestream_with_context这两个功能,也非常好用。
示例代码为:

#示例-11
from flask import send_from_directory

@app.route('/getfile', methods=['GET'])
def download_file():
    return send_from_directory(r"D:\Workspace\flask_source", "aa.txt", as_attachment=True)

Markup

class Markup(text_type):

将输入文本text_type标记为安全,不需要进行转移。
如果将HTML作为变量通过Jinjia模板的方式作为变量插入页面中,Flask会自动尝试对HTML进行转义。这是必要的安全措施,确保恶意用户通过提交一段恶意代码并显示在页面中,从而让其他用户的浏览器进行执行。Flask同时提供两种方法来对安全的HTML不转义直接显示:一个是利用Markup类,二是利用Jinjia关键字safe。示例代码为:

示例-12
from flask import Markup
@app.route("/")
def index():
    return Markup('Hello %s!') % '<strong>kejun</strong>'#显示strong标签

@app.route("/1")
def index1():
    return 'Hello %s!' % '<strong>kejun</strong>'#将strong标签转移成显示

current_app

应用上下文对象,官方文档有详细的介绍,

posted @ 2017-09-25 10:12  柯君  阅读(565)  评论(0编辑  收藏