1、初始化
在这章,你将学到Flask应用程序的不同部分。同时,你将编写和运行你的第一个Flask web应用程序。
所有的Flask应用程序都必须创建一个 应用程序实例 。使用web服务器网关接口协议将所有从客户端接收的请求传递给这个对象处理。这个应用程序实例就是Flask类的一个对象,通常使用下面的方式创建:
from flask import Flask
app = Flask(__name__)
Flask类构造函数唯一需要的参数就是应用程序的主模块或包。对于大多数应用程序,Python的name变量就是那个正确的、你需要传递的值。
注:对于Flask开发者来说,传给Flask应用程序构造函数的name参数是比较容易弄混淆的。Flask使用这个参数来确定应用程序的根目录,这样以后可以相对这个路径来找到资源文件。
稍后你可以看到更复杂的应用程序实例初始化,但是对于简单应用程序这些已经足够了。
2、路由和视图函数
客户端例如web浏览器发送 请求 给web服务,进而将它们发送给Flask应用程序实例。应用程序实例需要知道对于各个URL请求需要运行哪些代码,所以它给Python函数建立了一个URLs映射。这些在URL和函数之间建立联系的操作被称之为 路由 。
在Flask应程序中定义路由的最便捷的方式是通过显示定义在应用程序实例之上的app.route装饰器,注册被装饰的函数来作为一个路由。下面的例子会演示怎样使用装饰器来申明一个路由:
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
注:装饰器是Python语言的标准特性;它们可以以不同方式改变函数的行为。一个常见的模式是使用装饰器来注册函数作为一个事件处理程序。
在上一个示例给应用程序的根URL注册index()函数作为事件的处理程序。如果这个应用程序被部署在服务器上并绑定了 www.example.com 域名,然后在你的浏览器地址栏中输入 http://www.example.com 将触发index()来运行服务。客户端接收到的这个函数的返回值被称为 响应 。如果客户端是web浏览器,响应则是显示给用户的文档。
类似于index()的函数被称作 视图函数 。通过视图返回的响应可以是简单的HTML内容的字符串,但它也可以市更复杂的形式,正如您将看到的。
注:响应字符串嵌入在Python代码中导致代码难以掌控,在此只是介绍响应的概念。你将在第三章学习正确的方法来生成响应。
如果你注意到你每天使用的一些网站URLs如何形成的,你将会发现很多都有变量。例如,你的Facebook个人信息页的URL是 http://www.facebook.com/
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
用尖括号括起来的部分是动态的部分,所以任何URLs匹配到静态部分都将映射到这个路由。当视图函数被调用,Flask发送动态组件作为一个参数。在前面的示例的视图函数中,这个参数是用于生成一个个性的问候作为响应。
在路由中动态组件默认为字符串,但是可以定义为其他类型。例如,路由/user/
3、服务启动
应用程序实例有一个run方法用于启动Flask集成的web服务:
if __name__ == '__main__':
app.run(debug=True)
name == 'main'在此处使用是用于确保web服务已经启动当脚本被立即执行。当脚本被另一个脚本导入,它被看做父脚本将启动不同的服务,所以app.run()调用会被跳过。
一旦服务启动,它将进入循环等待请求并为之服务。这个循环持续到应用程序停止,例如通过按下Ctrl-C。
有几个选项参数可以给app.run()配置web服务的操作模式。在开发期间,可以很方便的开启debug模式,将激活 debugger 和 reloader 。这样做是通过传递debug为True来实现的。
注:Flask提供的web服务并不用于生产环境。你将在十七章学习生产环境的web服务。
4、一个完整的应用程序
在上一节,你学习了Flask web应用程序的不同部分,现在是时候写一个了。整个 hello.py 应用程序脚本只不过将前面描述的三个部分结合在一个文件中。应用程序示例2-1所示。
示例 hello.py:一个完整的Flask应用程序
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '
<h1>Hello World!</h1>
'
if __name__ == '__main__':
app.run(debug=True)
建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 2a来切换到这个版本的应用程序。
运行应用程序之前,请确保你在之前创建的虚拟环境已经是激活状态且已安装Flask。现在打开你的web浏览器并在地址栏输入 http://127.0.0.1:5000/ 。下图显示连接到应用程序后的web浏览器。
然后输入以下命令启动应用程序:
(venv) $ python hello.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
如果你输入任何其他URL,应用程序将不知道如何操作它并且将返回错误代码404给浏览器――当你访问一个不存在的网页也会得到该错误。
下面所示应用程序的增强版添加了第二个动态路由。当你访问这个URI,你应该可以看到一个个性的问候。
示例hello.py:带有动态路由的Flask应用程序
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, %s!</h1>
' % name
if __name__ == '__main__':
app.run(debug=True)
建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 2b来切换到这个版本的应用程序。
测试动态路由,确保服务正在运行随后访问 http://localhost:5000/user/Dave 。生成的应用程序会使用动态参数名响应一个定制的问候。尝试不同的名称,看看视图函数总是生成响应基于给定的名称。
5、请求-响应循环
现在你已经玩过一个基本的Flask应用程序,你也许想要知道更多关于Flask如何施展魔力。下面章节描述了一些框架设计方面的特点。
5.1、应用程序Context和请求Context
当Flask从客户端收到一个请求,它需要提供几个可用对象给视图函数处理。request对象是个不错的例子,它封装了客户端发送的HTTP请求。
Flask视图函数访问request对象的最好方式,就是作为一个参数发送它,但这需要每个单一视图函数在应用程序中有一个额外的参数。考虑一下,如果request对象不是唯一一个视图函数需要访问完成请求的对象,事情将会变得更加复杂。
为了避免弄乱视图函数那些可能需要或不需要的参数,Flask使用context来临时确定可访问的全局对象。也多亏了context,视图函数可以写成下面这样:
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中的不同对象。contexts使得Flask确定可访问的全局变量而不干扰其他线程。
注:线程是可以独立管理的最小指令序列。一个进程中有多个活动的线程是非常常见的,有时分享内存或文件句柄资源。多线程web服务器会启动一个线程池并从池中选择一个线程来处理每个传入的请求。
Flask有两类context:应用级context 和 请求级context。表2-1展示了这些context提供的变量。
Flask激活(或压栈)应用级context和请求级context在调度请求之前,然后删除他们当请求被处理后。当应用程序context被压入栈,线程中current_app和g变量变得可用;同样的,当请求级context被压入栈,request和session变量也同样变得可用。如果这些变量中的任何一个不是由激活的应用级或请求级context访问,会产生错误。在后面的章节会详细讨论四个context变量,所以不要担心你不理解它们的用处。
下面的Python shell会话演示了应用级context是如何工作的:
>>> from hello import app
>>> from flask import current_app
>>> current_app.name
Traceback (most recent call last):
...
RuntimeError: working outside of the application context
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>> current_app.name
'hello'
>>> app_ctx.pop()
在这个示例中,当应用级context没有激活,但是却作为有效的context被压入栈中,current_app.name报错。注意在应用程序实例中一个应用级context是如何通过调用app.app_context()来获得的。
5.2、请求调度
当一个应用程序收到客户端的请求,它需要找到响应的视图函数为之服务。对于这个任务,Flask会在应用程序的URL映射中查找请求的URL,该映射包含URLs和操作它们的视图函数。Flask通过app.route装饰器或非装饰器版本app.add_url_rule()来建立这个映射。
看一下Flask应用程序中URL映射是怎样的,你可以在Python shell中检查hello.py创建的映射。测试中,请确保你的虚拟环境是激活状态:
(venv) % python
>>> 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>])
/和/user/
URL映射中所示的HEAD、OPTIONS、GET元素为request方法,由路由处理。Flask连接方法到每个路由,这样不同的请求方法发送到相同的URL可以被不同的视图函数处理。HEAD和OPTIONS方法由Flask自动管理,所以实际上可以说,在这个应用程序中URL映射的三个路由都连接到GET方法了。在第四章你将学习为路由指定不同的请求方法。
5.3、请求Hooks
有些时候在每个请求处理之前或之后执行代码是非常有用的。例如,在开始每一个请求前可能有必要创建数据库连接,或对用户请求进行验证。为了避免复制处理这些操作的代码到每一个视图函数中,Flask给你选择注册相同函数来调用,在请求被分配给视图函数之前或之后。
请求hooks由装饰器实现。下面是四个Flask支持的hooks:
(1)before_first_request:在第一个请求被处理前注册一个函数运行。
(2)before_request:在每一个请求前注册一个函数运行。
(3)after_request:如果没有未处理的异常发生,在每一个请求后注册一个函数运行。
(4)teardown_request:即使未处理的异常发生,在每一个请求后注册一个函数运行。
在请求hook函数和视图函数之间共享数据的惯用方法就是使用g全局context。例如,before_request处理程序可以从数据库加载已登录的用户并保存在g.user中。之后,当视图函数被调用,可以从那访问用户。
请求hooks的示例会在未来的章节中展示给大家,所以不用担心,
5.4、响应
当Flask调用一个视图函数,并期望它的返回值去响应该请求。大多数的响应是将简单字符串构成的HTML页面发回给客户端。
但是HTTP协议需要比字符串更多的信息作为请求的响应。一个HTTP响应中非常重要的部分是状态码,Flask默认设置200来指示请求已经成功处理。
当视图函数需要用不同的状态码响应,可以在响应文本后添加数字码作为第二个返回值。例如,下面的视图函数返回400错误状态码的请求:
@app.route('/')
def index():
return '<h1>Bad Request</h1>', 400
视图函数返回的响应还可以携带第三个参数,添加一个头部字典给HTTP响应。通常很少用到,但是你可以在第十四章看到示例。
除了返回一个、两个或三个值的元组,Flask视图函数可以选择返回response对象。make_response()函数可携带一个、两个或三个参数,和视图函数返回的值一样,并返回一个response对象。有时候在视图函数中执行这个转换是非常有用的,然后使用response对象中的方法进一步配置响应。下面的示例创建response对象并设置cookie:
from flask import make_response
@app.route('/')
def index():
response = make_response('
<h1>This document carries a cookie!</h1>
')
response.set_cookie('answer', '42')
return response
有一类特殊的响应称作重定向。这类响应不包含页面文档;只是给浏览器一个新的URL去加载新的页面。重定向通常和web表单一起使用,你将在第四章学习。
重定向通常由302响应状态码注明并且重定向的URL由头部的Location给出。重定向响应可以使用三个值的返回生成,也可通过响应对象生成,但是鉴于它频繁的使用,Flask提供redirect()函数来创建这样的响应:
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.example.com')
另一个具有中断功能的特殊响应用来错误处理。下面的示例,当URL给出的id动态参数不是一个合法的用户时返回状态码404:
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
注意终止不是指将控制权返回给调用它的函数,而是指通过抛出异常将控制权返回给web服务。
6、Flask扩展
Flask是可扩展的。它故意腾出地给重要的功能,例如数据库和用户授权,给你自由去选择最适合你的应用程序的包,或写一个自己想要的。
社区开发了非常多的扩展用于各种用途,如果这还不够,可以使用任何Python标准包和库。为了让你了解一个扩展是如何并入一个应用程序的,下面的章节给hello.py添加一个扩展,增加应用程序的命令行参数。
6.1、Flask-Script命令行选项
Flask开发,其web服务器支持一系列的启动配置选项,但是配置它们的唯一方式只有在脚本中传递参数给app.run()并调用。这不是非常的方便,理想方法是通过命令行参数传递配置选项。
Flask-Script是给你的Flask应用程序添加命令行解释的扩展。它打包了一组通用的选项,还支持自定义命令。
使用pip安装扩展:
(venv) $ pip install flask-script
下面展示了在 hello.py 应用程序中添加命令行解释的变化。
示例. hello.py:使用Flask-Script
from flask.ext.script import Manager
manager = Manager(app)
# ...
if __name__ == '__main__':
manager.run()
专为Flask开发的扩展暴露在flask.ext命名空间下。Flask-Script从flask.ext.script中导出一个名为Manager的类。
初始化这个扩展的方法和其他许多扩展一样:主类实例的初始化是通过将应用程序实例作为参数传递给构造函数实现的。创建的对象适当的用于每一个扩展。在这个示例中,服务器启动通过manager.run()来路由,且命令行在这被解析。
建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 2c来切换到这个版本的应用程序。
因为这些变化,应用程序获得一组基本的命令行选项。运行hello.py显示可用信息:
$ python hello.py
usage: hello.py [-h] {shell, runserver} ...
positional arguments:
{shell, runserver}
shell 在Flask应用程序上下文的内部运行一个Python Shell。
runserver 运行Flask开发服务器,例如:app.run()
optional arguments:
-h, --help 显示这个帮助信息并退出
shell命令用于在应用程序上下文中启动一个Python shell会话。你可以使用这个会话去运行维护任务,或测试,或调试错误。
runserver命令,就像它的名称一样,启动web服务。运行python hello.py runserver在调试模式下启动web服务,还有更多的选项:
(venv) $ python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
[--processes PROCESSES] [--passthrough-errors] [-d]
[-r]
运行Flask开发服务器,例如:app.run()
optional arguments:
-h, --help 显示这个帮助信息并退出
-t HOST, --host HOST
-p PORT, --port PORT
--threaded
--processes PROCESSES
--passthrough-errors
-d, --no-debug
-r, --no-reload
--host参数是一个非常有用的选项,因为它能告诉web服务器监听哪个网络接口的客户端连接。默认,Flask开发的web服务器监听localhost的连接,所以只有来自内部计算机运行的服务器可以接收。下面的命令使得web服务器监听公网接口,其他网络上的计算机可以连接:
(venv) $ python hello.py runserver --host 0.0.0.0
* Running on http://0.0.0.0:5000/
* Restarting with reload
现在web服务器应该可以从网络中的任何一台计算机访问 http://a.b.c.d:5000 ,"a.b.c.d"是运行服务的计算机的外部IP地址。
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。