首頁  >  文章  >  後端開發  >  用Python的Flask框架來建構第一個Web應用

用Python的Flask框架來建構第一個Web應用

高洛峰
高洛峰原創
2017-03-03 15:30:253213瀏覽

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 &#39;<h1>Hello World!</h1>&#39;


註:裝飾器是Python語言的標準特性;它們可以以不同方式改變函數的行為。一個常見的模式是使用裝飾器來註冊函數作為一個事件處理程序。
在上一個範例給應用程式的根URL註冊index()函數作為事件的處理程序。如果這個應用程式被部署在伺服器上並綁定了 www.example.com 域名,然後在你的瀏覽器網址列中輸入 http://www.php.cn/ 將觸發index()來運行服務。客戶端接收到的這個函數的回傳值稱為 回應 。如果客戶端是web瀏覽器,則回應則是顯示給使用者的文件。

類似index()的函數被稱為 視圖函數 。透過視圖傳回的回應可以是簡單的HTML內容的字串,但它也可以市更複雜的形式,正如您將看到的。

註:回應字串嵌入在Python程式碼中導致程式碼難以掌控,在此只是介紹回應的概念。你將在第三章學習正確的方法來產生回應。
如果你注意到你每天使用的一些網站URLs如何形成的,你將會發現很多都有變數。例如,你的Facebook個人資訊頁的URL是 http://www.php.cn/;username> ,所以你的用戶名是它的一部分。 Flask在路由裝飾器中使用特殊的語法支援這些類型的URLs。下面的範例定義了一個擁有動態名稱元件的路由:


@app.route(&#39;/user/<name>&#39;) 
def user(name):
 return &#39;<h1>Hello, %s!</h1>&#39; % name


用尖括號括起來的部分是動態的部分,所以任何URLs匹配到靜態部分都會映射到這個路由。當視圖函數被調用,Flask發送動態元件作為一個參數。在前面的範例的視圖函數中,這個參數是用來產生一個個性的問候作為回應。

在路由中動態元件預設為字串,但是可以定義為其他類型。例如,路由/user/只符合有一個整數在id動態段的URLs。 Flask路由支援int、float和path。 path同樣是字串類型,但不認為斜線是分隔符,而認為它們是動態元件的一部分。

3、服務啟動
應用程式實例有一個run方法用於啟動Flask整合的web服務:


if __name__ == &#39;__main__&#39;:
 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 '

Hello World!

' if __name__ == &#39;__main__&#39;: app.run(debug=True)


建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 2a来切换到这个版本的应用程序。
运行应用程序之前,请确保你在之前创建的虚拟环境已经是激活状态且已安装Flask。现在打开你的web浏览器并在地址栏输入 http://www.php.cn/:5000/ 。下图显示连接到应用程序后的web浏览器。

用Python的Flask框架來建構第一個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 '

Hello World!

' @app.route('/user/') def user(name): return '

Hello, %s!

' % name if __name__ == &#39;__main__&#39;: app.run(debug=True)


建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 2b来切换到这个版本的应用程序。
测试动态路由,确保服务正在运行随后访问 http://localhost:5000/user/Dave  。生成的应用程序会使用动态参数名响应一个定制的问候。尝试不同的名称,看看视图函数总是生成响应基于给定的名称。

用Python的Flask框架來建構第一個Web應用


5.1、应用程序Context和请求Context

当Flask从客户端收到一个请求,它需要提供几个可用对象给视图函数处理。request对象是个不错的例子,它封装了客户端发送的HTTP请求。

Flask视图函数访问request对象的最好方式,就是作为一个参数发送它,但这需要每个单一视图函数在应用程序中有一个额外的参数。考虑一下,如果request对象不是唯一一个视图函数需要访问完成请求的对象,事情将会变得更加复杂。

为了避免弄乱视图函数那些可能需要或不需要的参数,Flask使用context来临时确定可访问的全局对象。也多亏了context,视图函数可以写成下面这样:


from flask import request

@app.route(&#39;/&#39;)
def index():
 user_agent = request.headers.get(&#39;User-Agent&#39;)
 return &#39;

<p>Your browser is %s</p>

&#39; % user_agent


注意,在这个视图函数中,request是如何被作为一个全局变量来使用的。现实中,request是不能作为全局变量的,如果是多线程服务器,同一时间线程作用于不同客户端的不同请求,所以每一个线程需要看到request中的不同对象。contexts使得Flask确定可访问的全局变量而不干扰其他线程。

注:线程是可以独立管理的最小指令序列。一个进程中有多个活动的线程是非常常见的,有时分享内存或文件句柄资源。多线程web服务器会启动一个线程池并从池中选择一个线程来处理每个传入的请求。
Flask有两类context:应用级context 和 请求级context。表2-1展示了这些context提供的变量。

用Python的Flask框架來建構第一個Web應用


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
&#39;hello&#39;
>>> 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 &#39;/&#39; (HEAD, OPTIONS, GET) -> index>,
 <Rule &#39;/static/<filename>&#39; (HEAD, OPTIONS, GET) -> static>,
 <Rule &#39;/user/<name>&#39; (HEAD, OPTIONS, GET) -> 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(&#39;/&#39;)
def index():
 return &#39;<h1>Bad Request</h1>&#39;, 400


视图函数返回的响应还可以携带第三个参数,添加一个头部字典给HTTP响应。通常很少用到,但是你可以在第十四章看到示例。

除了返回一个、两个或三个值的元组,Flask视图函数可以选择返回response对象。make_response()函数可携带一个、两个或三个参数,和视图函数返回的值一样,并返回一个response对象。有时候在视图函数中执行这个转换是非常有用的,然后使用response对象中的方法进一步配置响应。下面的示例创建response对象并设置cookie:


from flask import make_response

@app.route(&#39;/&#39;)
def index():
 response = make_response(&#39;

<h1>This document carries a cookie!</h1>

&#39;)
 response.set_cookie(&#39;answer&#39;, &#39;42&#39;)
 return response


有一类特殊的响应称作重定向。这类响应不包含页面文档;只是给浏览器一个新的URL去加载新的页面。重定向通常和web表单一起使用,你将在第四章学习。

重定向通常由302响应状态码注明并且重定向的URL由头部的Location给出。重定向响应可以使用三个值的返回生成,也可通过响应对象生成,但是鉴于它频繁的使用,Flask提供redirect()函数来创建这样的响应:


from flask import redirect

@app.route(&#39;/&#39;)
def index():
 return redirect(&#39;http://www.example.com&#39;)


另一个具有中断功能的特殊响应用来错误处理。下面的示例,当URL给出的id动态参数不是一个合法的用户时返回状态码404:


from flask import abort

@app.route(&#39;/user/<id>&#39;)
def get_user(id):
 user = load_user(id)
 if not user:
  abort(404)
 return &#39;

<h1>Hello, %s</h1>

&#39; % 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__ == &#39;__main__&#39;:
 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地址。

更多用用Python的Flask框架來建構第一個Web應用相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn