我是靠谱客的博主 坦率白猫,最近开发中收集的这篇文章主要介绍Flask程序的基本结构,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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()

请求上下文被推送后,就可以使用requestsession变量。

这四个上下文非常有用。

注意,在程序实例上调用 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程序的基本结构所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部