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程序的基本结构相关推荐

  1. Python Flask Web 第一课 —— 基本概念和程序的基本结构

    1. 初始化 所有的 Flask 程序都必须创建一个程序实例,所谓程序实例,在 Flask 框架下就是,Flask 类的实例对象(instance). from flask import Flask ...

  2. flask程序打包部署_如何使用Flask构建Web应用程序并将其部署到云中

    flask程序打包部署 by Salvador Villalon 萨尔瓦多·维拉隆(Salvador Villalon) 介绍 (Introduction) In each section, I wi ...

  3. [转载] 一、第一个Flask程序

    参考链接: Flask –(创建第一个简单的应用程序) 1.准备工作 前两篇文章已经部署好了python和flask的环境,接下来就是进入写代码阶段了,但是在本篇文章,我们先不写代码,先新建一个空的f ...

  4. The way to Go(6): Go程序的基本结构和要素

    Reference: Github: Go Github: The way to Go Go程序的基本结构和要素 helloworld.go: package mainimport "fmt ...

  5. 批量下载ABAP程序和表结构

    REPORT YGJH003 NO STANDARD PAGE HEADING LINE-SIZE 200 MESSAGE-ID WA. ******************************* ...

  6. QML 编程之旅 -- QML程序的基本结构概念

    文章目录 QML 文档的构成 QML基本语法 QML 编程之旅 – QML程序的基本结构概念 学习Qt编程快近一年了,的确是项目驱动,让我不得不咬紧牙关,需要快速的学习掌握一门新的技术.编程是一个非常 ...

  7. C语言程序的基本结构

    文章目录 一.C语言基础知识的学习方法 二.C语言程序开发的流程 三.安装C语言的编译器 四.C程序的基本结构 1.程序的注释 2.预处理指令 3.主函数的入口 4.主函数体 五.编译并执行 C 程序 ...

  8. 《Android UI基础教程》——1.2节Android 应用程序的基本结构

    本节书摘来自异步社区<Android UI基础教程>一书中的第1章,第1.2节Android 应用程序的基本结构,作者 [美]Jason Ostrander,更多章节内容可以访问云栖社区& ...

  9. python在哪些控制结构中使用else保留字_python的程序控制结构-循环结构与random库使用和圆周率案例--pyt...

    python的程序控制结构-循环结构与random库使用和圆周率案例--pyt python的程序控制结构-循环结构与random库使用和圆周率案例--python-7-days 循环结构 - for ...

最新文章

  1. 吴恩达《优化深度神经网络》精炼笔记(3)-- 超参数调试、Batch正则化和编程框架...
  2. for循环简介及实例(输出九九乘法表)
  3. vue中align_Vue的简单Treeview组件,没有额外的依赖——VueTeatree
  4. 年近而立,Java何去何从?
  5. 【java】窗口和流的应用
  6. HR套招的十大经典面试问题
  7. 福大研究生计算机学硕似录取,2017年福州大学数学与计算机学院专业型硕士研究生拟录取名单...
  8. Invalid hook call. Hooks can only be called inside of the body of a function
  9. 突发公共卫生事件应急指挥及决策系统解决方案
  10. Laragon 在Windows中快速搭建Laravel本地开发环境
  11. 一个标星 5.2k+ 的牛逼开源商城系统
  12. (十一)51单片机——用AT24C02实现存储秒表数据(附成果展示)
  13. 实现SSO单点登录的思考
  14. JSP实验-简单页面设计
  15. 网新恒天_点网新角度和点网新React
  16. 面包屑导航:最佳做法和示例
  17. 右键菜单中新建EXCEL丢失解决办法
  18. “回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。请写一个程序判断读入的字符串是否是“回文”。
  19. Windows系统搭建FTP服务器教程
  20. android圆角矩形图片的实现进而讨论view自定义的要点

热门文章

  1. 解决linux普通用户ls不显示颜色的问题
  2. 数据结构笔记(二十三)--哈夫曼树
  3. 计算机c盘如何扩大,电脑c盘怎么扩大
  4. java有没有友元函数_c++中友元函数理解与使用
  5. stackexchange.mysql_StackExchange.Redis加载Lua脚本进行模糊查询的批量删除和修改
  6. hosts文件 端口_中望软件:中望3D网络版服务端如何固定端口
  7. mysql5.7多源复制缺点_配置mysql5.7多源复制
  8. Java不满足的依赖异常_java – 新的缺失/不满足的依赖项WildFly 9中的错误
  9. java实现lru缓存_Java中的LRU缓存实现
  10. linux中nohup命令_Linux中的Nohup命令