Flask自带的常用组件介绍

[TOC]
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

#示例-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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容

  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,135评论 22 257
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,105评论 18 139
  • [TOC]一直想做源码阅读这件事,总感觉难度太高时间太少,可望不可见。最近正好时间充裕,决定试试做一下,并记录一下...
    何柯君阅读 7,035评论 3 98
  • 解释1: 允许将应用组织为模块,每个模块有自洽的 MVC,开发者做些工作可以使模块间依赖尽可能少,必要时可以按 b...
    大诗兄_zl阅读 2,158评论 1 1
  • 突然想起有张画好的一直没有发,那就拿出来吧,也差不多一个月木有更新了~ 素材来自宜家宣传册,属于比较简单的作品。 ...
    ipromiseido阅读 730评论 9 36