学习FLASK之二、基础的用应Flask结构

学习FLASK之二、基础的用应Flask结构

这一章你将学习Flask应用的不同部分。你将书写和运行第一个Flask应用。

初始化

所有的Flask应用必须创建一个应用实例。服务器传递从客户端获得的请求到这个对象从而进行处理,使用的协议为Web Server Gateway Interface (WSGI)应用实例是Flask类的对象。用如下方法创建:

from flask import Flask

app = Flask(__name__)

Flask类构造函数需要的唯一的参数是应用的主模块或包的名称。对于大部分应用,Python’的__name__就是正确的值。Flask通过name参数来确定应用的根路径,从而找到与应用相对的资源的路径。

路由和View函数

客户端如浏览器发送请求到网络服务器,服务器将请求发送给Flask应用实例。应用需要知道对于每一个URL请求需要运行什么代码,所以它要保留URLsPython函数的映射。一个URL与处理这个URL的函数的关联称为路由routeFlask应用中定义路由的最便利的方法是用应用实例暴露的app.route装饰器,它将装饰函数登记为路由。下面的例子说明如何用装饰器来声明一个路由:

@app.route('/')

def index():

return '<h1>Hello World!</h1>'

装饰器是 Python语言的标准特征,它们可以用来修改函数的行为。一个常用的模式是用装饰器来登记函数作为事件处理器。

上面的例子将index()登记为就用的根URL的处理函数。如果将用应布局到与域名www.example.com相关的服务器,那么在你的浏览器中导航到http://www.example.com 就会触发服务器上运行的index(),函数的返回值,称为响应,是客户端接收的结果。如果客户端是浏览器,响应就是用户显示的文档。

像index()这样的函数称为view函数。由view函数返回的响应可以是简单的带有HTML内容的字符串,但是也可以是更复杂的表单,你将在后面看到。嵌入到Python代码的响应字符串使代码难于维护,这里只是用来介绍响应的概念。你将在后面看到产生响应的更好的方法。

你要是留意一下你日常使用的URLs的组成什么样子的,你会发现许多URLs都包含可变的部分。例如你的Facebook的个人属性页为http://www.facebook

.com/<your-name>,所以你的username是URL的一部分。Flask用路由装饰器中的特定符号支持这种URLs。下面的代码定义一个有动态名称部分的路由:

@app.route('/user/<name>')

def user(name):

return '<h1>Hello, %s!</h1>' % name

角括号里的是动态部分,所以任何与静态部分匹配的URLs都会映射到这个路由。当view函数被调用时,Flask将发送动态部分作为参数。上面的view函数的例子中,这个参数用来产生个性化的欢迎响应。

黙认情况下,路由中的动态部分是字符串,但是也可以用类型定义。例如,路由 /user/<int:id>将匹配在动态部分含有整数的URLs。Flask支持int, float,和path作为路由。path是一种字符串,但是不会把斜杠当作分隔符而是作为动态部分的组成。

服务器的启动

应用实例用run方法来启动Flask集成的网络服务器:

if __name__ == '__main__':

app.run(debug=True)

这里使用的Python惯用语__name__ == '__main__'确保服务器只在脚本直接执行时启动。如果该脚本被其它脚本引用则它认为母脚本会启动不同的服务器所以会跳过 app.run() 一旦启动服务器,它就会进入循环以等待请求并处理请求。循环直到应用停止,例如按下Ctrl-C

app.run()可以有多个参数来配置服务器的操作模式。在开发时,使用debug模式是很便利的,这可用通过将debug参数设为debug来实现。

Flask提供的服务器不是用于生产环境的,你可以在后面学习关于生产环境的服务器。

完整的应用

前面你已经学习了Flask web应用的不同部分,现在是时候来写一个完整的应用了。整个hello.py应用脚本只不过是将前面介绍的三个部分组合到一个文件而已。完整的代码如下见:

http://www.aluoyun.cn/details.php?article_id=189

要运行这个应用,请确保你创建的虚拟环境被激活并已安装Flask然后用以下命令启动应用:

(venv) $ python hello.py

* Running on http://127.0.0.1:5000/

* Restarting with reloader

现在打开浏览器并导航到http://127.0.0.1:5000/

         

如果你输入别的URL,应用不知道如何处理它,因此会返回404错误代码给浏览器。这是当你导航到不存在的网页里得到的熟悉的错误。 

这个应用的改版本是在路由中添加动态部分,当你访问这个URL时,你会得到个性化的欢迎。

完整的代码见:

http://www.aluoyun.cn/details.php?article_id=190

为了测试动态路由,请确保服务器是运行的,然后导航到http://

localhost:5000/user/Dave应用会用定制的欢迎作出响应,由name动态参数产生。你可用尝试不同的name观察view函数的响应。

      

请求响应循环

你已经尝试了基础的Flask应用了,你想了解更多关于Flask是如何工作的。下面介绍一些Flask框架的设计方面。

应用与请求上下文

当Flask获得来自客户端的请求时,它需要为view函数提供一些对象来处理请求。一个很好的例子是request object,它包含了客户端发送的HTTP。Flask给view函数访问request object的明显的方法是将它作为参数发送,但是这要求每一个view函数有一个额外的参数。当request object不是 view函数的唯一参数时,情况会变得复杂。为了避免view函数中聚集过多的需要或不需要的参数,Flask使用contexts来临时的使一些对象全局的访问。因为contextsview函数可以像下面的代码一样书写:

from flask import request

@app.route('/')

def index():

user_agent = request.headers.get('User-Agent')

return '<p>Your browser is %s</p>' % user_agent

这个 view函数里,request作为全局变时使用。实际上,request在同一时刻不同的线程处理来自不同客户端的不同requests的多线程服务器里不能作为作局变量,因此每一个线程需要不同的request对象。Contexts可以确保一些变量被线程全局访问而不干扰别的线程。

线程是可以被独立处理的最小的指令序列。进行有多个活动的线程是很常见的,有时共享内存或文件句柄。多线程网络服务器启动线程池并从池中选择一个线程来处理每一个请求。

Flask里有两种contextsapplication context request context

下表展示这些contexts暴露的变量

2-1. Flask context globals

变量名    Va            context          描述riable name Context ion

current_app    Application context    激活的应用的应用实例。

g              Application context    应用用来在处理请求时临时贮存的对象。每次请求会重置这个变量。

request        Request context       

请求对象,它包括客户端发送的HTTP请求的内容。

session        Request context         用户会话,应用用来存贮不同请求“记住”的值的字典。

Flask在分派请求前激活 (pushes) applicationrequest contexts处理完请求后将它们删除。当application context被激活时,current_app  g 变量可以被线程使用;同样,当request context被激活时, requestsession可以被线程使用。如果没有激活的application request Context或以访问这些变量,则产生错误。后面会详细的介绍种上下文变量。现在不用担心你还不理解为什么它们是有用的。

下面Python shell会话展示application context是如何工作的:

>>> from hello import app

>>> from flask import current_app

>>> current_app.name

Traceback (most recent call last):

...

RuntimeError: working outside of application context

>>> app_ctx = app.app_context()

>>> app_ctx.push()

>>> current_app.name

'hello'

>>> app_ctx.pop()

个例子里, 当没有application context激活时current_app.name失败,但是一旦被激活就可以使用。 留意一下 application context通过调用应用实例的app.app_context() 获得。

请求分派

当应用获得客户端的请求时,它需要知道用那个view函数来处理请求。对于这种任务,Flask从应用的URL map中的请求查找URLURL map包含了URLsview函数的映射。Flask通过app.route装饰器或等价的非装饰器版的app.add_url_rule()来建立这种映射。

想知道application 应用中的URL map看来起如何,你可以用Python shell检查hello.py产生的map对于个测试,请确保你的虚拟环境被激活。

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

这个应用的app.route装饰器定义了/ /user/<name>路由。

/static/<filename> 路由是Flask添加的用来访问静态文件的特殊路由。你将在后面学习静态文件。

URL map中的HEAD, OPTIONS, GET元素是路由处理的请求方法。Flask将方法邦定到路由以便不同的请求发送到相同的URL可以用不同的view函数处理。

HEADOPTIONS方法是Flask自动处理的,所以实际上可以说URL map中的三个路由都邦定到GET方法。后面会学习路由的不同请求方法。

请求钩子Request Hooks

有时候需要在处理请求前或后执行代码。例如,请求开始前需要创建数据库连接或用户授权。不需要在每个view函数里重复这些代码, Flask提供了选项来登记共用的函数以便在请求分派给view函数前后调用。

Request hooks作为装饰器实施。Flask提供了4种hooks:

• before_first_request: 登记一个函数在第一个请求处理前运行。

• before_request: 登记一个函数在每个请求前运行。

• after_request: 登记一个函数在每个请求处理之后运行,如果没有未处理的意外发生。

• teardown_request: 登记一个函数在每一个处理之后运行,即便有意外发生。

请求钩子函数与 view函数共享数据的常见模式是使用g全局上下文变量。例如before_request句柄可以从数据库中加载登录的用户并贮存在g.user. Later,当view函数被调用时,它可以从g.user. Later访问用户。

我们将在后面介绍request hooks的例子,所以不用担心现在还没理解。 

响应

Flask调用view函数时,它期望返回值是对请求的响应。大多数情况下响应是送回客户端的作为HTML网页的简单的字串。

但是 HTTP协议要求对请求的响应不只是字符串。HTTP响应的一个重要部分是状态码,黙认情况下 Flask将它设为200表示请求执行成功。

view函数需要响应不同的状态码时,它可以添加数字代码作为响应文本的第二个返回值。 例如,下面的view函数返回400状态码,表示请求错误:

@app.route('/')

def index():

return '<h1>Bad Request</h1>', 400

view函数返回的响应也可以有第三个参数,HTTP响应的headers字典。这不是很常见,但是后面的例子可以看到。

不是将1,2,3个值作为tuple返回,Flask view函数有Response object选项。make_response()函数可以取1,2,3个参数,可以从一个view函数返回相同的值,并返回Response object。

有时在view函数里进行这种转换是有用的,然后用响应对象的方法来配置响应。下面的例子创建一个响应对象然后在对象里设置一个 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,浏览器可以从这个URL加载新页面。重定向通常在网页的表单中使用。后面会学到。

重定向通常用302响应码表示并在Location header中给出新的 URL重定向可以用三个值的返回来产生, 或者使用响应对象,但是由于重定向经常便用,Flask提供了一个redirect()帮助函数,它可以产生重定响。 例如:

from flask import redirect

@app.route('/')

def index():

return redirect('http://www.example.com')

另一种特殊的响应由abort函数产生,它用于错误处理。下面的例子产生404代码,如果URL提供的id动态参数不能表示一个有效的用户:

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

注意 abort不会将控制权返回调用它的函数而是将控制权返回网络服务器通过产生意外。

    Flask扩展

Flask是可扩展的。对于重要的功能如数据库,用户授权等,你可以自由的选择适合于你的应用的包,你也可以根据需要自已写。社区里有许多扩展库,也可以使用标准的Python包或库。为了让你认识一下扩展是如何集成到应用的,下面在hello.py 里增加扩展以用命令行参数改进应用。

Flask-Script的命令行选项

Flask的开发服务器提供了多个启动配置选项,但是指明它们的方法只能是通过传递参数到 脚本的app.run()里。这不够方便,更好的方法是通过命令行参数传递配置选项。

Flask-Script Flask的一个扩展,它为你的 Flask应用增加一个命令行解析器。它包含一般的选项,也可以自定义命令。通过pip安装这个扩展:

(venv) $ pip install flask-script

下面展示给hello.py增加命令行解析器需增加的代码:

Example 2-3. hello.py: Using Flask-Script

from flask_script import Manager

manager = Manager(app)

# ...

if __name__ == '__main__':

manager.run()

针对Flask的扩展需要使用flask_名字空间。

Flask-Script导出一个称这Manager的类,它从flask_script导入。初始化这个扩展的方法与别的扩展一样:主类的实例化通过传递应用实例给构造函数作为参数而初始化。然后使用创建的对象。本例中,服务器的启动通过manager.run()命令行在这里被解析。

通过这些改变,应用获得基础的命令行选项集。

现以过行hello.py会提示用法消息:

$ python hello.py

usage: hello.py [-h] {shell,runserver} ...

positional arguments:

{shell,runserver}

shell Runs a Python shell inside Flask application context.

runserver Runs the Flask development server i.e. app.run()

optional arguments:

-h, --help show this help message and exit

shell命令用来启动应用上下文的Python shell会话。你可以用这个会话来运行维护任务或测试,或调试。

runserver命令,正如它的名字所示,启动网络服务器。

    运行python hello.py runserver将启动调试模式的网络服务器,但是还是很多的选项可用:

(venv) $ python hello.py runserver --help

usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]

[--processes PROCESSES] [--passthrough-errors] [-d]

[-r]

Runs the Flask development server i.e. app.run()

optional arguments:

-h, --help show this help message and exit

-t HOST, --host HOST

-p PORT, --port PORT

--threaded

--processes PROCESSES

--passthrough-errors

-d, --no-debug

-r, --no-reload

--host参数告诉服务器临听那个接器以连接客户端。黙认情况下Flask的开发服务器监听 localhost所以只接受来自计算机内部的连接。下面的命令使服务器监听公共网络的连接,从而可以连接网络上的计算机:

(venv) $ python hello.py runserver --host 0.0.0.0

* Running on http://0.0.0.0:5000/

* Restarting with reloader

现在服务器可以被网络上的任何计算机访问,通过导航到http://

a.b.c.d:5000, 其中“a.b.c.d”是运行服务器的计算机的外网IP地址。本章介绍请求响应的概念,但是关于响应还有很多内容。Flask提供了很好的支持以便用模板来产生响应,这是下一章要介绍的很重要的主题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lishaoan77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值