概述
Flask程序的基本结构
@(Flask)
初始化
程序实例是Flask类的对象。
常常用的代码是:
from flask import Flask
app = Flask(__name__)
Flask类的构造函数只有一个必须制定的参数:程序主模块或包的名字。
Flask用这个参数决定程序的根目录,以便稍后能找到相对于程序根目录的资源文件位置。
P.S : 后续会有更复杂些的初始化方式。
路由和视图函数
- 客户端将请求发送给Web服务器
- Web服务器将请求发送给**Flask程序实例**app
- app需要知道:对每个URL请求运行哪些代码,那么这个就需要映射关系,保存映射关系的程序是路由
定义路由器
最简便的方式:使用app.route
修饰器
@app.route('/')
def index(): #index()函数注册为程序根地址的处理程序
return '<h1>Hello World</h1>'
修饰器:Python语言的标准特性,可以使用不同的方式修改函数的行为。惯用做法是:使用修饰器把函数注册为事件的处理程序。
上例即为:
访问www.xxxx.com,会触发服务器调用index()
函数进行处理。
其中函数的返回值称之为响应。
index()
也称作:视图函数(View Function)。
视图函数的返回值可以是以下:
- 包含HTML的字符串
- 复杂的表单
一般来说,响应函数返回响应字符串不是好的写法,生成响应的正确方式后文会继续讲。
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' %name
尖括号中的是动态内容,任何能匹配静态部分的URL都会映射到这个路由上。
视图函数将动态部分作为参数传入函数,因此这也是一种传参方式。
其中,动态部分,默认使用字符串,也可以用类型定义:/user/<int:id>
,仅仅匹配动态片段id为整数的URL。
Flask支持的动态类型
- int
- float
- path : 也是字符串,但不把斜线视作分隔符,会将其当做动态片段的一部分。
启动服务器 : run
if __name__ == '__main__':
app.run(debug=True) #启用调试模式
__name__ == '__main__'
是Python的约定用法,确保执行这个脚本时才启动Web服务器。
服务器启动后会进入轮训,等待并处理请求。
P.S Flask提供的Web服务器不适合在生产环境使用。
完整程序的样子
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
if __name__ == '__main__':
app.run(debug=True)
在虚拟环境已经激活的情况下:
python hello.py
将会弹出:
(venv) WangdeMacBook-Pro:flask rick$ python hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 163-598-392
在浏览器即可输入http://127.0.0.1:5000/
进行访问。
这样就是简单的打通了服务器和客户端之间的通道。
这个hello.py不必刻意放在哪,只需要有Flask的环境即可运行。请求将交给Flask实例,也即有Flask即可。
请求–响应循环
进一步了解Flask的工作方式。
程序和请求上下文
Flask从客户端收到请求时,要让视图函数能访问一些对象,只有这样才能处理请求。
这个很好理解,无论是在Java还是在C#,网络编程中总是封装好了常用的一些对象,如response,request,session等六大对象。
request对象封装了客户端发送的HTTP请求。
那么问题在于,如何做到让视图函数能访问其他对象呢?
- 想法一:将其作为参数传入视图函数 – 问题:导致每视图函数都增加一个参数。
所以这个想法不可行。
实际解决方式是: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不可能作为全局变量。
原因:多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的request对象必然不同。
所以,Flask使用上下文让特定的变量在一个线程中全局可访问,而不会干扰到其他线程。
多线程服务器创建一个线程池,再从线程池中选择一个线程用于处理接收到的请求。
两种上下文
- 程序上下文
- current_app : 当前激活程序的程序实例
- g : 处理请求时用作临时存储的对象。每次请求都重置这个变量。
- 请求上下文
- request : 请求上下文。请求对象,封装客户端发出的HTTP请求的内容
- session : 请求上下文。用户会话。用于存储请求之间需要记住的值的词典。
具体解释就是:Flask在分发请求之前,激活/推送程序上下文和请求上下文。
请求处理完成后再将其删除。
注意,在程序实例上调用ctx = app.app_context()
可获得一个程序上下文。
- 上下文推送:
ctx.push()
- 上下文推出:
ctx.pop()
请求上下文被推送后,就可以使用request
和session
变量。
这四个上下文非常有用。
注意,在程序实例上调用 app.app_context() 可获得一个程序上 下文。
请求调度
程序收到客户端发来的请求时,要找到处理该请求的视图函数。
为完成这个任务,需要:
- 在URL映射中找到请求的URL,URL映射是URL和视图函数之间的对应关系
- Flask用
app.route
修饰器或者非修饰器形式的app.add_url_rule()
生成映射。
查看映射键值对:
from hello import app
app.url_map
#返回结果
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])
可以看到两个键值对是我们自己通过修饰器为视图函数添加的,其中有一个是默认的。
/static/<filename>
是Flask添加的特殊路由,注意这个也是动态参数的url,用于访问静态文件。
P.S HEAD,OPTIONS方法由Flask自动处理,这里的三个路由都使用GET方法。关于如何为路由指定不同的请求方法后序会继续说明。
请求钩子(hook)
在处理请求之前或之后执行代码。
通用函数的使用:可能在请求被分发到视图函数之前,或者之后调用,如注册函数。
请求钩子的实现:基于修饰器实现。
支持的四种钩子:
- before_first_request : 注册一个函数,处理第一个请求前运行
- before_request : 注册一个函数,每次请求前运行
- after_request : 注册一个函数,如果没有异常抛出,每次请求之后运行
- teardown_request : 注册一个函数,即使有异常抛出,也在每个请求之后运行
注意:请求钩子函数和视图函数之间共享数据,使用上下文全局变量g
来进行。
这个类似于ASP.NET的ViewBag。
e.g. 钩子函数里可以在g.user
保存用户名,视图函数可以通过g.user
拿到数据。
响应
一般情况下,响应就是简单的字符串,作为HTML页面送回到客户端。
但是,HTTP协议响应中一个很重要的部分是状态码,默认200表示被成功处理。
数字作为第二个参数返回。
@app.route('/')
def index():
return '<h1>Bad Request</h1>',400
视图函数返回的响应还可以接受第三个参数:由首部组成的字典,添加到HTTP响应中。一般不必这么做。
from flask import make_response
@app.route('/')
def inde():
response = make_response('<h1>This document carries a cookie!</h1>')
response.set_cookie('answer','42')
return response
make_response()
函数可接受1个,2个或者3个参数(与视图函数返回值相同),此函数返回一个Response对象。
针对这个response实例,可以进一步设置响应内容。
页面重定向
特殊响应累心个,此类响应没有页面文档,只告诉浏览器一个新地址用于加载新页面。
重定向的使用场景:常常在Web表单中使用。
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.xxxx.com')
重定向经常使用的状态码是302,指向的地址由Location首部提供。用三个值形式的返回值生成,但是因为使用频繁,提供了redirect()
辅助函数用于生成这种响应。
特殊响应之abort
用于处理错误。
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
P.S. abort
不会把控制权还给调用它的函数,而是抛出异常把控制权交给服务器。
Flask扩展
添加扩展样例。
使用Flask-Script支持命令行选项
Flask的开发服务器(不适合生产环境的服务器),支持很多启动设置选项,但是只能在脚本中作为参数传给app.run()
函数。
可见,这种方式不是很方便,理想方式:使用命令行参数。
Flask-Script
是个Flask扩展,可以实现这个效果。
安装
pip install flask-script
转为Flask开发的扩展都暴露在flask.ext
命名空间下。
Flask-Script输出了一个名为Manager
的类,从flask.ext.script
中引入。
这种扩展的初始化方法适用于其他很多扩展:把程序实例作为参数传递给构造函数,像是托管。
不引入扩展的程序由`app.run()启动服务器,引入此扩展的,就交给扩展来启动服务器。
if __name__ == '__main__':
manager.run()
启动服务器:py hello.py runserver
也可以指定参数:py hello.py runserver --host 0.0.0.0
学习自 Flask Web开发实战。
最后
以上就是坦率白猫为你收集整理的Flask程序的基本结构的全部内容,希望文章能够帮你解决Flask程序的基本结构所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复