狗书无敌,天下第一(初识flask)
Posted 向前跑,带着冷眼与嘲笑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了狗书无敌,天下第一(初识flask)相关的知识,希望对你有一定的参考价值。
为什么选择使用flask?
和其他框架相比, Flask 之所以能脱颖而出,原因在于它让开发者做主,使其能对程序具有全面的创意控制。
在 Flask 中,你可以自主选择程序的组件,如果找不到合适的,还可以自己开发。
Flask 提供了一个强健的核心, 其中包含每个 Web 程序都需要的基本功能,而其他功能则交给行业系统中的众多第三方扩展。
一句话概括就是flask不是一个高度定制化的web框架,你可以做到随心所欲,使用任何可能的扩展来完成你的项目。
狗书的代码已上传GitHub:Companion code to my O\'Reilly book "Flask Web Development。
Flask 有两个主要依赖:路由、调试和 Web 服务器网关接口(Web Server Gateway Interface,WSGI)子系统由 Werkzeug(http://werkzeug.pocoo.org/)提供;模板系统由 Jinja2(http://jinja.pocoo.org/)提供。 Werkzeug 和 Jinjia2 都是由 Flask 的核心开发者开发而成。
Flask 并不原生支持数据库访问、 Web 表单验证和用户认证等高级功能。这些功能以及其他大多数 Web 程序中需要的核心服务都以扩展的形式实现, 然后再与核心包集成。
安装
pip install flask
初始化
所有 Flask 程序都必须创建一个程序实例。 Web 服务器使用一种名为 Web 服务器网关接口(Web Server Gateway Interface, WSGI)的协议,把接收自客户端的所有请求都转交给这个对象处理。
from flask import Flask app = Flask(__name__)
Flask接受一个字符串作为参数,这个参数决定程序的根目录,以便于能找到相对于程序根目录的资源文件的位置,通常这种情况下都使用 __name__作为Flask参数。
也就是说,此时web框架接收的请求都会通过flask实例化的对象进行处理。
这里的初始化方式是最简单的初始化方式,后面会使用到更为复杂的初始化方式。
路由和视图函数
程序实例需要知道对每个 URL 请求运行哪些代码,所以保存了一个 URL 到Python 函数的映射关系。处理 URL 和函数之间关系的程序称为路由。
在 Flask 程序中定义路由的最简便方式,是使用程序实例提供的 app.route 修饰器,把修饰的函数注册为路由。
@app.route(\'/\') def index(): return \'<h1>Hello World!</h1>\'
这个函数的返回值称为响应,是客户端接收到的内容。如果客户端是 Web 浏览器, 响应就是显示给用户查看的文档(一般就是html页面)。
程序实例用 run 方法启动 Flask 集成的开发 Web 服务器:
if __name__ == \'__main__\': app.run(debug=True)
有一些选项参数可被 app.run() 函数接受用于设置 Web 服务器的操作模式。在开发过程中启用调试模式会带来一些便利, 比如说激活调试器和重载程序。要想启用调试模式, 我们可以把 debug 参数设为 True。
第一个程序:
from flask import Flask app = Flask(__name__) @app.route(\'/\') def index(): return \'<h1>Hello World!</h1>\' @app.route(\'/user/<name>\') def user(name): return \'<h1>Hello, {}!</h1>\'.format(name) if __name__ == \'__main__\': app.run()
为了避免大量可有可无的参数把视图函数弄得一团糟, Flask 使用上下文临时把某些对象变为全局可访问。有了上下文,就可以写出下面的视图函数:
from flask import request @app.route(\'/\') def index(): user_agent = request.headers.get(\'User-Agent\') return \'<p>Your browser is %s</p>\' % user_agent
这里我们把request当作全局变量使用,实际生产中每个线程都处理不同的请求,那么他们的request必然是不同的。Falsk 使用上下文让特定的变量在一个线程中全局可访问,与此同时却不会干扰其他线程。
request就是一种python中的ThreadLocal对象。
只在线程中是全局变量。
#转载至csdn,http://blog.csdn.net/hyman_c/article/details/52548540 import threading localobj = threading.local()#flask中的request就是这样的概念 def threadfunc(name): localobj.name = name print(\'localobj.name is %s\' % name) if __name__ == \'__main__\': t1 = threading.Thread(target=threadfunc, args=(\'Hyman\',)) t2 = threading.Thread(target=threadfunc, args=(\'liuzhihui\',)) t1.start() t2.start() t1.join() t2.join()
在多线程服务器中客户端每建立一个链接,服务器就创建一个线程,每个线程中就会有一个request来表示客户端的链接请求信息。
flask上下文全局变量
没激活程序上下文之前就调用 current_app.name 会导致错误,但推送完上下文之后就可以调用了。 注意,在程序实例上调用 app.app_context() 可获得一个程序上下文。ctx.push()是激活上下文的操作,类似的,如果我们想要回收上下文,用ctx.pop()。
from hello import app from flask import current_app app_ctx = app.app_context() app_ctx.push() current_app.name \'hello\'
from flask import g g.name=\'manno\'
g作为flask程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据。
request请求对象,封装了客户端发送的HTTP请求的内容。
session用户会话,用来记住请求(比如前后一个GET请求和一个POST请求)之间的值,从数据格式上来说它是字典类型。它存在于连接到服务器的每个客户端中,属于私有存储,会保存在客户端的cookie中。
session[\'name\']=form.name.data
URL 映射是 URL 和视图函数之间的对应关系。Flask 使用 app.route 修饰器或者非修饰器形式的 pp.add_url_rule() 生成映射。
app.url_map Map([<Rule \'/\' (GET, HEAD, OPTIONS) -> index>, <Rule \'/static/<filename>\' (GET, HEAD, OPTIONS) -> static>, <Rule \'/user/<name>\' (GET, HEAD, OPTIONS) -> user>])
/ 和 /user/<name> 路由在程序中使用 app.route 修饰器定义。 /static/<filename> 路由是Flask 添加的特殊路由,用于访问静态文件。
请求钩子
Flask 支持以下 4 种钩子。
before_first_request:注册一个函数,在处理第一个请求之前运行。
before_request:注册一个函数,在每次请求之前运行。
after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。
注:在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 g。例如, before_request 处理程序可以从数据库中加载已登录用户,并将其保存到 g.user 中。随后调用视
图函数时,视图函数再使用 g.user 获取用户。
flask中具有四种钩子被做成了修饰器,我们在后端可以进行调用做相关的操作.使用钩子函数时,我们需要借助flask的全局变量g.g作为中间变量,在钩子函数和视图函数中间传递数据.我们先引入全局变量g。
第一步,引入全局变量g
from flask import g
第二步, 然后注册一个视图函数,用来显示g中的数据
@app.route(\'/test\') def test(): return g.string
这里我们使用request之前的钩子
@app.before_first_request def bf_first_request(): g.string = \'before_first_request\'
此时运行此路由显示的是g中传递的string变量(当然也可以不返回进行其他操作)。
响应
flask的响应包括模板(本质是字符串)和状态码。
@app.route(\'/\') def index(): return \'<h1>Bad Request</h1>\', 400
如果不想返回由 1 个、 2 个或 3 个值组成的元组, Flask 视图函数还可以返回 Response 对象。 make_response() 函数可接受 1 个、 2 个或 3 个参数(和视图函数的返回值一样),并
返回一个 Response 对象。
from flask import make_response @app.route(\'/\') def index(): response = make_response(\'<h1>This document carries a cookie!</h1>\') response.set_cookie(\'answer\', \'42\')#创建对象,给对象加cookie return response
flask重定向
from flask import redirect @app.route(\'/\') def index(): return redirect(\'http://www.example.com\')
abort生成响应404,abort 不会把控制权交还给调用它的函数,而是抛出异常把控制权交给 Web 服务器。
from flask import abort @app.route(\'/user/<id>\') def get_user(id): user = load_user(id) if not user: abort(404) return \'<h1>Hello, %s</h1>\' % user.name
使用Flask-Script支持命令行选项
Flask 的开发 Web 服务器支持很多启动设置选项,但只能在脚本中作为参数传给 app.run()函数。这种方式并不十分方便,传递设置选项的理想方式是使用命令行参数。
Flask-Script 是一个 Flask 扩展,为 Flask 程序添加了一个命令行解析器。 Flask-Script 自带了一组常用选项,而且还支持自定义命令。
pip install flask-script
from flask.ext.script import Manager manager = Manager(app) if __name__ == \'__main__\': manager.run()
专为 Flask 开发的扩展都暴漏在 flask.ext 命名空间下。 Flask-Script 输出了一个名为Manager 的类,可从 flask.ext.script 中引入。
这个扩展的初始化方法也适用于其他很多扩展: 把程序实例作为参数传给构造函数,初始化主类的实例。 创建的对象可以在各个扩展中使用。在这里,服务器由 manager.run() 启
动,启动后就能解析命令行了。
from flask import Flask from flask_script import Manager app = Flask(__name__) manager = Manager(app) @app.route(\'/\') def index(): return \'<h1>Hello World!</h1>\' @app.route(\'/user/<name>\') def user(name): return \'<h1>Hello, %s!</h1>\' % name if __name__ == \'__main__\': manager.run()
使用manager可以增加自定义命令
from flask_script import Manager app = Flask(__name__) manager=Manager(app) @manager.command def print_str(): print(\'hello world\') if __name__ == \'__main__\': manager.run()
设置cookie
@app.route(\'/set_cookie\') def set_cookie(): response=make_response(\'Hello World\'); response.set_cookie(\'Name\',\'Hyman\') return response
我们还可以指定cookie的有效时长,下面的代码把有效时长设置成了30天.通常情况下,我们还可以在浏览器上设置cookie的有效时长,而且浏览器上配置的有效时长优先级要高于我们在代码中设置的。
outdate=datetime.datetime.today() + datetime.timedelta(days=30) response.set_cookie(\'Name\',\'Hyman\',expires=outdate)
获取cookie
@app.route(\'/get_cookie\') def get_cookie(): name=request.cookies.get(\'Name\') return name
<h1>My name is {{request.cookies.get(\'Name\')}}</h1> {#html模板中获取cookie#}
删除cookie(三种方式)
(1) 可以通过在浏览器中设置来清除cookie
(2) 使用Response的set_cookie进行清除
@app.route(\'/del_cookie\') def del_cookie(): response=make_response(\'delete cookie\') response.set_cookie(\'Name\',\'\',expires=0) return response
(3)使用Response的 delete_cookie方法
@app.route(\'/del_cookie2\') def del_cookie2(): response=make_response(\'delete cookie2\') response.delete_cookie(\'Name\') return response
Jinja2模板引擎
Jinja2模板引擎是flask默认的模板引擎。
Flask 提供的 render_template 函数把 Jinja2 模板引擎集成到了程序中 。使用方式与django的render基本一致。
Jinja2 能识别所有类型的变量, 甚至是一些复杂的类型,例如列表、字典和对象。
<p>A value from a dictionary: {{ mydict[\'key\'] }}.</p> <p>A value from a list: {{ mylist[3] }}.</p> <p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p> <p>A value from an object\'s method: {{ myobj.somemethod() }}.</p>
jinja2很大程度上和django的模板语言很类似,包括过滤器的使用,判断,循环,模板继承等。
来说点特别的,jinja2支持宏(类似于函数,使用也和函数很像)。
定义及使用宏:
{% macro render_comment(comment) %} <li>{{ comment }}</li> {% endmacro %} <ul> {% for comment in comments %} {{ render_comment(comment) }} {% endfor %} </ul>
重复使用宏需要将其保存在单独的文件中,然后在需要使用的模板中导入:
{% import \'macros.html\' as macros %} <ul> {% for comment in comments %} {{ macros.render_comment(comment) }} {% endfor %} </ul>
除了重复使用宏的方式还可以重复导入代码块。
common.html
<h1>我是重复的代码片</h1>
导入这个代码块
{% include \'common.html\' %} {% include \'common.html\' %} {% include \'common.html\' %} {% include \'common.html\' %} <h1>Hello World</h1>
jinja2还支持与django模板一样的模板继承功能。
要想在flask程序中集成 Bootstrap, 显然要对模板做所有必要的改动。不过,更简单的方法是使用一个名为 Flask-Bootstrap 的 Flask 扩展(这也是我喜欢flask的原因之一吧,扩展性强,插件还很多),简化集成的过程。
pip install flask-bootstrap
初始化 Flask-Bootstrap
from flask.ext.bootstrap import Bootstrap bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之后,就可以在程序中使用一个包含所有 Bootstrap 文件的基模板。
{% extends "bootstrap/base.html" %} {% block title %}Flasky{% endblock %}
{% 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"> <div class="page-header"> <h1>Hello, {{ name }}!</h1> </div> </div> {% endblock %}
自定制错误页面
@app.errorhandler(404) def page_not_found(e): return render_template(\'404.html\'), 404 @app.errorhandler(500) def internal_server_error(e): return render_template(\'500.html\'), 500
url_for() 函数最简单的用法是以视图函数名(或者 app.add_url_route() 定义路由时使用的端点名)作为参数, 返回对应的 URL。例如,在当前版本的 hello.py 程序中调用 url_for(\'index\') 得到的结果是 /。调用 url_for(\'index\', _external=True) 返回的则是绝对地址,在这个示例中是 http://localhost:5000/。
使用 url_for() 生成动态地址时,将动态部分作为关键字参数传入。例如, url_for(\'user\', name=\'john\', _external=True) 的返回结果是 http://localhost:5000/user/john。
如果 Web 程序的用户来自世界各地,那么处理日期和时间可不是一个简单的任务。
有一个使用 javascript 开发的优秀客户端开源代码库,名为 moment.js(http://momentjs.com/),它可以在浏览器中渲染日期和时间。 Flask-Moment 是一个 Flask 程序扩展,能把moment.js 集成到 Jinja2 模板中。
pip install flask-moment
此模块依赖于moment.js 和jquery.js
from datetime import datetime @app.route(\'/\') def index(): return render_template(\'index.html\',current_time=datetime.utcnow())
渲染当前时间:
{% block scripts %} {{ super() }} {{ moment.include_moment() }} {% endblock %} <p>The local date and time is {{ moment(current_time).format(\'LLL\') }}.</p> <p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
{{moment.lang("zh-CN")}}//设置语言 {{moment().format(\'YYYY-MM-DD,h:mm:ss a\')}}//设置时间格式 常用格式化参数 YYYY 2014 年份 YY 14 2个字符表示的年份 Q 1..4 季度 M MM 4..04 月份 MMM MMMM 4月..四月 根据moment.locale()中的设置显示月份 D DD 1..31 一月中的第几天 Do 1日..31日 一月中的第几天 DDD DDDD 1..365 一年中的第几天 X 1410715640.579 时间戳 x 1410715640579 时间戳
flask表单处理
pip install flask-wtf
为了实现 CSRF 保护, Flask-WTF 需要程序设置一个密钥。 Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。设置密钥的方法
app = Flask(__name__) app.config[\'SECRET_KEY\'] = \'hard to guess以上是关于狗书无敌,天下第一(初识flask)的主要内容,如果未能解决你的问题,请参考以下文章