Flask 程序的基本结构

程序的基本结构

当我活着,我要做生命的主宰,而不做它的奴隶。 –佚名

2.1 初始化

所有 Flask 程序都必须创建一个程序实例.


from flask import Flask

app = Flask(__name__)

Flask 类的构造函数只有一个必须指定的参数,即程序主模块或者包的名字,在大多数程序中 Python 的 __name__变量就是所需的值

2.2 路由和视图函数

路由,在 Flask 中定义路由的最简便方式,是使用程序实例提供的 app.route 修饰器,把修饰的函数注册为路由


@app.route("/")
def index():
   return  '<h1>Hello</h1>'

前例把 index()函数注册为程序跟地址的处理程序,如果部署程序的服务器域名为 www.example.com 在浏览器中访问 www.example.com 会触发服务器执行 index()函数.这个函数的返回值称为响应,是客户端接收到的内容,如果客户端是 Web 浏览器,响应就是显示给用户查看的文档

像 index()这样的函数称为视图函数(view function)视图函数返回的响应可以是 HTML 的简单字符串,也可以是复杂的表单

动态的路由

  • 字符串类型

@app.route("/user/<username>")
def index(username):
   return  f'<h1>Hello {username}</h1>'   #必须有f
  • 数字类型

@app.route("/user/<int:id>")
def index(username):
   return  f'<h1>Hello {id}</h1>'

2.3 启动服务器

  • 程序中实例用 run 方法启动 Flask 集成开发的 WEb 服务器

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

__name__ =’__main__‘是 Python 常用的方法 它的作用就是直接执行这个脚本才会启动服务器,如果这个脚本是被引入的,当模块化的话 程序不会执行 app.run()

服务器启动后会进入轮询,等待并处理请求,轮询会一直运行,直到程序停止,或者按 CTRL+C

有一些选项参数可以被 app.run()函数接受 并且用于 Web 服务器的操作,在开发过程中 启动调试模式会带来一些便利,比如说激活调试器或者重载程序之类的。要是想启用调试模式,我们可以把 debug 变为 True

2.4 一个完整的程序

  • 把前面三部分整合在一起,host 是为了除了本机,同一个局域网以外的电脑能访问,port 端口号

# 引入flask
from flask import Flask

app = Flask(__name__)

# 写路由

@app.route("/")
def index():
      return '<h1>Hello,World!</h1>'

# 判断是否模块还是入口

if __name__ == '__main__':
   app.run(host='0.0.0.0',debug=True,port=5000)

  • 下面增加 2 个动态路由

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>Hello world</h1>'

@app.route('/user/<username>')
def user(username):
    return f'<h1>Hello {username}</h1>'

@app.route('/user/<username>/<int:id>')

def userid(username,id):
    return f'<h1>HaHa {username} 序号是{id}</h1>'


if __name__=='__main__':
    app.run(host='0.0.0.0',debug=True,port=5000)

2.5 请求响应循环

程序和请求

Flask 从客户端收到请求后,要让视图函数能访问一些对象,这样才能处理请求.请求对象就是一个很好的例子,它封装了客户端发送的 HTTP 请求

要想让视图能够访问请求对象,一个显而易见的方式是将其作为参数传入视图的参数,不过这会倒是程序中每个视图函数都增加一个参数.除了访问请求对象,如果视图函数在处理请求的时候还要访问其他对象,情况会更糟

为了避免大量可有可无的参数把视图函数弄乱,Flask 使用上下文临时把某些对象变成全局可访问,有了上下文就可以写出视图函数


from flask import Flask
from flask import request
app = Flask(__name__)

@app.route("/browers")
def browers():
    user_agent = request.headers.get('User-Agent')
    return f'<p> Your Browers is {user_agent}</p>'

if __name__=='__main__':
    app.run(host='0.0.0.0',debug=True,port=5000)

注意在这个试图函数中 我们把 request 当作全局变量使用.事实上 request 不可能是全局变量.多线程同时处理不同客户端发送的不同的请求时,每个线程看到的 request 必然不同.Flask 使用上下文让特定的变量在一个线程中全局可以访问,与此同时却不会干扰其他线程

线程是可单独管理的最小指令集.进程经常使用多个活动线程,有时还会共享内存或文件等等资源。多线程 Web 服务器会创建一个线程池,再从线程池中选择一个线程用于处理接受到的请求

  • 在 Flask 中有两种上下文,程序上下文和请求上下文
变量名 上下文 说明
current_app 程序上下文 当前激活程序的程序实例
g 程序上下文 处理请求时用作临时存储的对象,每次请求都会重设这个变量
request 请求上下文 请求对象封装了客户端发出的 HTTP 请求中的内容
session 请求上下文 用户会话,用于存储请求之间需要记住的值的词典

请求钩子函数

在 Flask 中提供了钩子函数,有时在处理请求之前或者之后 执行代码会很有用.

Flask 支持 4 种钩子函数

  • before_first_request: 注册一个函数 在处理第一个请求之前运行

  • before_request: 注册一个函数 在每次请求之前运行

  • after_request: 注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行(有异常就不执行)

  • teardown_request: 注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行(不管有没有都执行)

在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 g,例如 before_request 处理程序可以从数据库中加载已登陆的用户,并将其保存到 g.user 中,随后调用视图函数时,视图函数再使用 g.user 获取用户

响应

Flask 调用视图函数后,会将其返回值作为响应的内容。大多数情况响应就是一个简单的字符串,作为 HTML 页面回送客户端

  • 返回元祖 第一个内容,第二个状态码,第三个返回的 header 加上自定义属性

@app.route("/404")
def notfound():
    return '<h1>Bad request </h1>', 404,{'Locateion':'www.baidu.com'}

  • 返回一个字符串

@app.route('/test')
def test():
    return 'hello world!'
  • 返回渲染的模板

@app.route('/test2')
def test2():
    return render_template('index.html')
  • 返回 JSON jsonify

@app.route('/test3')
def test3():
   return jsonify({'name':'Tom'})
  • 返回 make_response

@app.route('/test4')
def test4():
    response = make_response('hello')
    response.headers = {'Location':'abc'}
    response.set_cookie('name','Tom')
    return response
  • 重定向

@app.route('/login')
def rediectPage():
    return redirect('http://www.baidu.com')
  • 还有一种特殊的响应,用于处理错误 about 函数生成,在下面例子中如果 URL 中动态参数 id 对应的用户不存在,就返回状态码 404,请看代码

@app.route('/test5/<int:id>')
def get_user(id):
    if not id:
      abort(404)
    return f'<h1>Hello{id}</h1>'

abort 不会把控制权交还给其他调用的函数,而是抛出异常把控制权交给服务器

  • 返回静态文件

@app.route('/returnstatic')
def returnstatic():
    return url_for('static',filename='路径')

文章作者: 雾烟云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 雾烟云 !
  目录