如何在 Web 中使用 Python — Python 文档
如何在网络中使用 Python
- 作者
- 马雷克·库比卡
抽象的
本文档展示了 Python 如何适应网络。 它提供了一些将 Python 与 Web 服务器集成的方法,以及对开发 Web 站点有用的一般实践。
自“Web 2.0”兴起以来,Web 编程已成为一个热门话题,“Web 2.0”专注于网站上用户生成的内容。 一直可以使用 Python 来创建网站,但这是一项相当乏味的任务。 因此,已经创建了许多框架和辅助工具来帮助开发人员创建更快、更健壮的站点。 本 HOWTO 描述了一些用于将 Python 与 Web 服务器结合以创建动态内容的方法。 这并不是一个完整的介绍,因为这个主题太广泛了,无法在一个单独的文档中涵盖。 但是,提供了最流行的库的简短概述。
也可以看看
虽然本 HOWTO 试图在 Web 中提供 Python 的概述,但它并不总是如所期望的那样最新。 Python 中的 Web 开发正在迅速发展,因此 Web Programming 上的 wiki 页面可能与最近的开发更加同步。
低级视图
当用户进入网站时,他们的浏览器会连接到该网站的 Web 服务器(这称为 请求 )。 服务器在文件系统中查找文件并将其发送回用户浏览器,浏览器显示它(这是响应)。 这大致就是底层协议 HTTP 的工作方式。
动态网站不是基于文件系统中的文件,而是基于在请求到来时由 Web 服务器运行的程序,这些程序 生成 返回给用户的内容。 他们可以做各种有用的事情,例如显示公告板的帖子、显示您的电子邮件、配置软件或仅显示当前时间。 这些程序可以用服务器支持的任何编程语言编写。 由于大多数服务器都支持 Python,因此很容易使用 Python 创建动态网站。
大多数 HTTP 服务器是用 C 或 C++ 编写的,因此它们不能直接执行 Python 代码——服务器和程序之间需要一个桥梁。 这些桥,或者说接口,定义了程序如何与服务器交互。 已经有许多尝试创建尽可能最好的界面,但只有少数值得一提。
并非每个 Web 服务器都支持每个接口。 许多 Web 服务器只支持旧的、现已过时的接口; 但是,它们通常可以使用第三方模块进行扩展以支持更新的模块。
通用网关接口
这个接口最常被称为“CGI”,是最古老的接口,几乎所有开箱即用的 Web 服务器都支持。 使用 CGI 与其 Web 服务器通信的程序需要由服务器为每个请求启动。 因此,每个请求都会启动一个新的 Python 解释器——这需要一些时间来启动——从而使整个界面仅可用于低负载情况。
CGI 的优点是它很简单——编写一个使用 CGI 的 Python 程序大约只需三行代码。 这种简单性是有代价的:它对开发人员的帮助很少。
编写 CGI 程序虽然仍然可行,但不再推荐。 使用 WSGI(本文档稍后介绍的主题),可以编写模拟 CGI 的程序,因此如果没有更好的选项可用,它们可以作为 CGI 运行。
用于测试 CGI 的简单脚本
要测试您的 Web 服务器是否支持 CGI,您可以使用这个简短的 CGI 程序:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# enable debugging
import cgitb
cgitb.enable()
print "Content-Type: text/plain;charset=utf-8"
print
print "Hello World!"
根据您的 Web 服务器配置,您可能需要使用 .py
或 .cgi
扩展名保存此代码。 此外,出于安全原因,此文件可能还需要位于 cgi-bin
文件夹中。
您可能想知道 cgitb
行是关于什么的。 这一行可以显示一个很好的回溯,而不仅仅是崩溃并在用户的浏览器中显示“内部服务器错误”。 这对于调试很有用,但它可能会冒着将一些机密数据暴露给用户的风险。 因此,您不应在生产代码中使用 cgitb
。 你应该 总是 捕捉异常,并显示正确的错误页面——最终用户不喜欢在他们的浏览器中看到不伦不类的“内部服务器错误”。
在您自己的服务器上设置 CGI
如果您没有自己的 Web 服务器,则这不适用于您。 您可以检查它是否按原样运行,如果不是,则需要与 Web 服务器的管理员交谈。 如果是大主机,你可以尝试提交一张请求 Python 支持的票。
如果您是自己的管理员或想在自己的计算机上设置 CGI 用于测试目的,则必须自己配置。 没有单一的方法来配置 CGI,因为有许多具有不同配置选项的 Web 服务器。 目前使用最广泛的免费 Web 服务器是 Apache HTTPd,或简称 Apache。 Apache 可以使用系统的包管理工具轻松安装在几乎每个系统上。 lighttpd 是另一种选择,据说性能更好。 在许多系统上,也可以使用包管理工具安装此服务器,因此可能不需要手动编译 Web 服务器。
- 在 Apache 上,您可以查看 Dynamic Content with CGI 教程,其中描述了所有内容。 大多数情况下,只需设置
+ExecCGI
就足够了。 本教程还描述了可能出现的最常见的问题。 - 在 lighttpd 上你需要使用 CGI 模块 ,它可以通过简单的方式进行配置。 归结为正确设置
cgi.assign
。
CGI 脚本的常见问题
在尝试运行这些脚本时,使用 CGI 有时会导致一些小麻烦。 有时看似正确的脚本无法按预期工作,原因是一些难以发现的小隐藏问题。
其中一些潜在的问题是:
- Python 脚本未标记为可执行文件。 当 CGI 脚本不可执行时,大多数 Web 服务器会让用户下载它,而不是运行它并将输出发送给用户。 为了使 CGI 脚本在类 Unix 操作系统上正常运行,需要设置
+x
位。 使用chmod a+x your_script.py
可以解决这个问题。 - 在类 Unix 系统上,程序文件中的行尾必须是 Unix 样式的行尾。 这很重要,因为 Web 服务器检查脚本的第一行(称为 shebang)并尝试运行在那里指定的程序。 它很容易被 Windows 行尾(回车和换行,也称为 CRLF)混淆,因此您必须将文件转换为 Unix 行尾(仅换行,LF)。 这可以通过以文本模式而不是二进制模式通过 FTP 上传文件来自动完成,但首选方式只是告诉您的编辑器以 Unix 行结尾保存文件。 大多数编辑器支持这一点。
- 您的 Web 服务器必须能够读取该文件,并且您需要确保权限正确。 在类 Unix 系统上,服务器通常以用户和组
www-data
运行,因此可能值得尝试更改文件所有权,或使用chmod a+r your_script.py
使文件世界可读。 - Web 服务器必须知道您尝试访问的文件是 CGI 脚本。 检查您的 web 服务器的配置,因为它可能被配置为期望 CGI 脚本的特定文件扩展名。
- 在类 Unix 系统上,shebang (
#!/usr/bin/env python
) 中解释器的路径必须正确。 此行调用/usr/bin/env
来查找 Python,但如果没有/usr/bin/env
,或者 Python 不在 Web 服务器的路径中,则会失败。 如果您知道 Python 的安装位置,也可以使用该完整路径。 命令whereis python
和type -p python
可以帮助您找到它的安装位置。 知道路径后,您可以相应地更改shebang:#!/usr/bin/python
。 - 该文件不得包含 BOM(字节顺序标记)。 BOM 用于确定 UTF-16 和 UTF-32 编码的字节顺序,但一些编辑器也将其写入 UTF-8 文件。 BOM 会干扰 shebang 行,所以一定要告诉你的编辑不要写 BOM。
- 如果网络服务器使用 mod_python,
mod_python
可能有问题。mod_python
能够自行处理 CGI 脚本,但它也可能成为问题的来源。
mod_python
来自 PHP 的人经常发现很难掌握如何在 Web 中使用 Python。 他们首先想到的大多是mod_python,因为他们认为这相当于mod_php
。 实际上,有很多不同之处。 mod_python
所做的是将解释器嵌入到 Apache 进程中,从而通过不必为每个请求启动 Python 解释器来加速请求。 另一方面,它不像 PHP 经常与 HTML 混合那样“Python 与 HTML 混合”。 与它等效的 Python 是模板引擎。 mod_python
本身功能更强大,并提供对 Apache 内部的更多访问。 它可以模拟 CGI,在“Python 服务器页面”模式(类似于 JSP)下工作,即“HTML 与 Python 混合”,并且它有一个“发布者”,它指定一个文件来接受所有请求并决定如何处理它们.
mod_python
确实有一些问题。 与 PHP 解释器不同,Python 解释器在执行文件时使用缓存,因此对文件的更改将需要重新启动 Web 服务器。 另一个问题是基本概念——Apache 启动子进程来处理请求,不幸的是,每个子进程即使不使用它也需要加载整个 Python 解释器。 这会使整个 Web 服务器变慢。 另一个问题是,因为 mod_python
链接到 libpython
的特定版本,所以不可能从旧版本切换到新版本(例如 2.4 到 2.5) 无需重新编译 mod_python
。 mod_python
也绑定到 Apache web 服务器,因此为 mod_python
编写的程序无法在其他 web 服务器上轻松运行。
这就是为什么在编写新程序时应避免使用 mod_python
的原因。 在某些情况下,使用 mod_python
进行部署仍然是一个好主意,但是 WSGI 也使得在 mod_python
下运行 WSGI 程序成为可能。
FastCGI 和 SCGI
FastCGI和SCGI试图以另一种方式解决CGI的性能问题。 它们不是将解释器嵌入到 Web 服务器中,而是创建长时间运行的后台进程。 Web 服务器中仍有一个模块,它使 Web 服务器可以与后台进程“对话”。 由于后台进程独立于服务器,它可以用任何语言编写,包括 Python。 该语言只需要一个库来处理与网络服务器的通信。
FastCGI 和 SCGI 的区别非常小,因为 SCGI 本质上只是一个“更简单的 FastCGI”。 由于 Web 服务器对 SCGI 的支持有限,大多数人使用 FastCGI 代替,其工作方式相同。 几乎所有适用于 SCGI 的内容也适用于 FastCGI,因此我们只介绍后者。
如今,FastCGI 从未被直接使用过。 就像mod_python
一样,只用于部署WSGI应用。
设置 FastCGI
每个 Web 服务器都需要一个特定的模块。
- Apache 有 mod_fastcgi 和 mod_fcgid。
mod_fastcgi
是原始版本,但它有一些许可问题,这就是为什么它有时被认为是非免费的。mod_fcgid
是一种更小、兼容的替代方案。 这些模块之一需要由 Apache 加载。 - lighttpd 自带 FastCGI 模块 以及 SCGI 模块 。
- nginx 也支持 FastCGI。
安装并配置模块后,您可以使用以下 WSGI 应用程序对其进行测试:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from cgi import escape
import sys, os
from flup.server.fcgi import WSGIServer
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
yield '<h1>FastCGI Environment</h1>'
yield '<table>'
for k, v in sorted(environ.items()):
yield '<tr><th>%s</th><td>%s</td></tr>' % (escape(k), escape(v))
yield '</table>'
WSGIServer(app).run()
这是一个简单的 WSGI 应用程序,但您需要先安装 flup,因为 flup 处理底层 FastCGI 访问。
也可以看看
有一些关于 使用 WSGI 设置 Django 的文档,其中大部分可以重用于其他符合 WSGI 的框架和库。 只需要改变manage.py
部分,这里使用的例子可以代替。 Django 或多或少做了同样的事情。
mod_wsgi
mod_wsgi 试图摆脱低级网关。 鉴于 FastCGI、SCGI 和 mod_python 主要用于部署 WSGI 应用程序,因此 mod_wsgi 开始直接将 WSGI 应用程序嵌入到 Apache Web 服务器中。 mod_wsgi 专门设计用于托管 WSGI 应用程序。 它使 WSGI 应用程序的部署比使用其他需要胶水代码的低级方法更容易部署。 缺点是 mod_wsgi 仅限于 Apache Web 服务器; 其他服务器需要自己的 mod_wsgi 实现。
mod_wsgi 支持两种模式:嵌入模式,它与 Apache 进程集成,以及守护进程模式,更像 FastCGI。 与 FastCGI 不同,mod_wsgi 自己处理工作进程,这使得管理更容易。
退一步:WSGI
WSGI 已经被多次提及,所以它必须是重要的。 事实上确实如此,现在是解释它的时候了。
Web 服务器网关接口,或简称 WSGI,在 PEP 333 中定义,是目前进行 Python Web 编程的最佳方式。 虽然它非常适合编写框架的程序员,但普通的 Web 开发人员不需要直接接触它。 在选择 Web 开发框架时,最好选择一个支持 WSGI 的框架。
WSGI 的一大好处是统一了应用程序编程接口。 当您的程序与 WSGI 兼容时——这在外层意味着您使用的框架支持 WSGI——您的程序可以通过任何具有 WSGI 包装器的 Web 服务器接口进行部署。 您无需关心应用程序用户是使用 mod_python 还是 FastCGI 或 mod_wsgi——使用 WSGI,您的应用程序将在任何网关接口上运行。 Python 标准库包含自己的 WSGI 服务器,wsgiref,这是一个可以用于测试的小型 Web 服务器。
一个非常棒的 WSGI 特性是中间件。 中间件是围绕您的程序的一层,可以为其添加各种功能。 已经有相当多的 中间件 可用。 例如,无需编写自己的会话管理(HTTP 是一种无状态协议,因此要将多个 HTTP 请求与单个用户关联,您的应用程序必须通过会话创建和管理此类状态),您只需下载执行此操作的中间件,插入并继续编写应用程序的独特部分。 压缩也是一样——现有的中间件可以使用 gzip 处理压缩 HTML 以节省服务器带宽。 身份验证是另一个可以使用现有中间件轻松解决的问题。
尽管 WSGI 可能看起来很复杂,但学习的初始阶段可能会非常有益,因为 WSGI 和相关的中间件已经为开发网站时可能出现的许多问题提供了解决方案。
WSGI 服务器
用于连接各种低级网关(如 CGI 或 mod_python)的代码称为 WSGI 服务器 。 其中一台服务器是 flup
,它支持 FastCGI 和 SCGI,以及 AJP。 其中一些服务器是用 Python 编写的,如 flup
,但也有其他服务器是用 C 编写的,可以用作替代品。
已有许多服务器可用,因此几乎可以在任何地方部署 Python Web 应用程序。 这是 Python 与其他 Web 技术相比的一大优势。
案例研究:MoinMoin
WSGI 为 Web 应用程序开发人员提供了什么? 让我们看一下已经存在一段时间的应用程序,它是用 Python 编写的,没有使用 WSGI。
MoinMoin 是最广泛使用的维基软件包之一。 它创建于 2000 年,因此比 WSGI 早了大约三年。 旧版本需要单独的代码才能在 CGI、mod_python、FastCGI 和独立上运行。
它现在包括对 WSGI 的支持。 使用 WSGI,可以在任何符合 WSGI 的服务器上部署 MoinMoin,无需额外的胶水代码。 与 WSGI 之前的版本不同,这可能包括 MoinMoin 的作者一无所知的 WSGI 服务器。
模型-视图-控制器
术语 MVC 经常出现在诸如“框架 foo 支持 MVC”之类的陈述中。 MVC 更多的是关于代码的整体组织,而不是任何特定的 API。 许多 Web 框架使用此模型来帮助开发人员为他们的程序带来结构。 较大的 Web 应用程序可能包含大量代码,因此从一开始就拥有一个有效的结构是一个好主意。 这样,即使其他框架(甚至其他语言,因为 MVC 不是 Python 特定的)的用户也可以轻松理解代码,因为他们已经熟悉 MVC 结构。
MVC 代表三个组件:
- 型号 。 这是将要显示和修改的数据。 在 Python 框架中,该组件通常由对象关系映射器使用的类表示。
- 视图 。 该组件的工作是向用户显示模型的数据。 通常这个组件是通过模板实现的。
- 控制器 。 这是用户和模型之间的层。 控制器对用户操作做出反应(比如打开一些特定的 URL),告诉模型在必要时修改数据,并告诉视图代码显示什么,
虽然人们可能认为 MVC 是一种复杂的设计模式,但实际上并非如此。 它被用在 Python 中是因为它被证明对于创建干净、可维护的网站很有用。
笔记
虽然并非所有 Python 框架都明确支持 MVC,但通过将数据逻辑(模型)与用户交互逻辑(控制器)和模板(视图)分离来创建使用 MVC 模式的网站通常是微不足道的。 这就是为什么不要在模板中编写不必要的 Python 代码很重要的原因——它与 MVC 模型背道而驰,并在代码库中造成混乱,使其更难理解和修改。
网站的成分
网站是复杂的结构,因此已经创建了工具来帮助 Web 开发人员使他们的代码更易于编写和维护。 此类工具适用于所有语言的所有 Web 框架。 开发人员不会被迫使用这些工具,而且通常没有“最佳”工具。 值得学习一下可用的工具,因为它们可以大大简化开发网站的过程。
模板
一些库使得 HTML 和 Python 代码的混合成为可能。 虽然一开始很方便,但它会导致代码非常难以维护。 这就是模板存在的原因。 在最简单的情况下,模板就是带有占位符的 HTML 文件。 填充占位符后,HTML 将发送到用户的浏览器。
Python 已经包含两种构建简单模板的方法:
>>> template = "<html><body><h1>Hello %s!</h1></body></html>"
>>> print template % "Reader"
<html><body><h1>Hello Reader!</h1></body></html>
>>> from string import Template
>>> template = Template("<html><body><h1>Hello ${name}</h1></body></html>")
>>> print template.substitute(dict(name='Dinsdale'))
<html><body><h1>Hello Dinsdale!</h1></body></html>
要基于非平凡的模型数据生成复杂的 HTML,通常需要条件和循环结构,如 Python 的 for 和 if。 模板引擎支持这种复杂的模板。
有许多可用于 Python 的模板引擎,它们可以在有或没有 框架 的情况下使用。 其中一些定义了一种易于学习的纯文本编程语言,部分原因是它的范围有限。 其他人使用 XML,并且保证模板输出始终是有效的 XML。 还有许多其他变化。
一些 框架 提供自己的模板引擎或特别推荐一个。 在没有理由使用不同的模板引擎的情况下,使用框架提供或推荐的模板引擎是一个好主意。
流行的模板引擎包括:
也可以看看
有许多模板引擎在争夺注意力,因为在 Python 中创建它们非常容易。 wiki 中的页面 Templating 列出了大量且不断增长的这些。 上面列出的三个被认为是“第二代”模板引擎,是一个很好的起点。
数据持久化
数据持久化虽然听起来很复杂,但其实就是存储数据。 这些数据可能是博客条目的文本、公告板上的帖子或维基页面的文本。 当然,有许多不同的方法可以在 Web 服务器上存储信息。
通常,使用 MySQL 或 PostgreSQL 等关系数据库引擎是因为它们在处理由数百万个条目组成的非常大的数据库时具有良好的性能。 还有一个叫做SQLite的小型数据库引擎,它与Python捆绑在sqlite3模块中,并且只使用一个文件。 它没有其他依赖项。 对于较小的站点,SQLite 就足够了。
使用称为 SQL 的语言对关系数据库进行 查询 。 Python 程序员一般不太喜欢 SQL,因为他们更喜欢使用对象。 可以使用称为 ORM(对象关系映射)的技术将 Python 对象保存到数据库中。 ORM 在底层将所有面向对象的访问转换为 SQL 代码,因此开发人员无需考虑。 大多数 框架 使用 ORM,而且效果很好。
第二种可能性是将数据存储在普通的纯文本文件(有时称为“平面文件”)中。 这对于简单的网站来说非常容易,但如果网站对存储的数据执行多次更新,则很难做到正确。
第三种可能性是面向对象的数据库(也称为“对象数据库”)。 这些数据库以一种与程序执行期间对象在内存中的结构方式非常相似的形式存储对象数据。 (相比之下,ORM 将对象数据存储为表中的数据行以及这些行之间的关系。)直接存储对象的优点是几乎所有对象都可以直接保存,这与关系数据库中的某些对象非常相似。很难代表。
Frameworks通常会提示选择哪种数据存储方法。 坚持框架推荐的数据存储通常是一个好主意,除非应用程序有特殊要求,可以通过替代存储机制更好地满足。
也可以看看
- Persistence Tools 列出了如何在文件系统中保存数据的可能性。 其中一些模块是标准库的一部分
- 数据库编程帮助选择保存数据的方法
- SQLAlchemy,最强大的Python OR-Mapper,以及Elixir,让SQLAlchemy更容易使用
- SQLObject,另一个流行的 OR-Mapper
- ZODB 和 Durus,两个面向对象的数据库
构架
创建代码以运行网站的过程涉及编写代码以提供各种服务。 无论相关网站的复杂性或目的如何,提供特定服务的代码通常以相同的方式工作。 将这些常见的解决方案抽象为可重用的代码,就产生了所谓的 Web 开发“框架”。 也许最著名的 Web 开发框架是 Ruby on Rails,但 Python 有自己的框架。 其中一些部分受到 Rails 的启发,或者借鉴了 Rails 的想法,但许多在 Rails 之前就已经存在很长时间了。
最初,Python Web 框架倾向于将开发网站所需的所有服务整合为一个巨大的集成工具集。 没有两个 Web 框架是可互操作的:如果没有大量的重新设计工作,为一个开发的程序就无法部署在另一个框架上。 这导致了“极简主义”Web 框架的开发,该框架仅提供在 Python 代码和 http 协议之间进行通信的工具,所有其他服务都通过单独的组件添加到顶部。 开发了一些特别标准,允许框架之间有限的互操作性,例如允许不同模板引擎互换使用的标准。
自 WSGI 出现以来,Python Web 框架世界一直在朝着基于 WSGI 标准的互操作性发展。 现在,许多 Web 框架,无论是“全栈”(提供部署最复杂网站所需的所有工具)还是极简框架,或介于两者之间的任何框架,都是由可与多个框架一起使用的可重用组件集合构建的。
大多数用户可能希望选择具有活跃社区的“全栈”框架。 这些框架往往都有很好的文档记录,并提供了在最短的时间内生成功能齐全的网站的最简单途径。
一些值得注意的框架
框架的数量令人难以置信,因此无法在此处全部涵盖。 相反,我们将简要介绍一些最受欢迎的。
姜戈
Django 是一个由几个紧密耦合的元素组成的框架,这些元素是从头开始编写的,并且可以很好地协同工作。 它包含一个功能强大且易于使用的 ORM,并具有出色的在线管理界面,可以使用浏览器编辑数据库中的数据。 模板引擎是基于文本的,旨在供不会编写 Python 的页面设计人员使用。 它支持模板继承和过滤器(其工作方式类似于 Unix 管道)。 Django 捆绑了许多方便的功能,例如创建 RSS 提要或通用视图,这使得几乎无需编写任何 Python 代码即可创建网站成为可能。
它有一个庞大的国际社区,其成员创建了许多网站。 还有很多附加项目扩展了 Django 的正常功能。 这部分是由于 Django 写得很好的 在线文档 和 Django 书 。
涡轮齿轮
另一个流行的 Python 网络框架是 TurboGears。 TurboGears 采用了使用现有组件并将它们与胶水代码相结合的方法来创建无缝体验。 TurboGears 为用户提供了选择组件的灵活性。 例如,可以更改 ORM 和模板引擎以使用与默认使用的包不同的包。
该文档可以在 TurboGears 文档 中找到,其中可以找到截屏视频的链接。 TurboGears 还拥有一个活跃的用户社区,可以回答大多数相关问题。 还出版了一本 TurboGears 书 ,这是一个很好的起点。
TurboGears 的最新版本 2.0 版在支持 WSGI 和基于组件的架构方面更进一步。 TurboGears 2 基于另一个流行的基于组件的 Web 框架 Pylons 的 WSGI 堆栈。
佐普
Zope 框架是“旧的原始”框架之一。 它目前在 Zope2 中的化身是一个紧密集成的全栈框架。 其最有趣的功能之一是它与称为 ZODB(Zope 对象数据库)的强大对象数据库紧密集成。 由于其高度集成的特性,Zope 最终进入了一个有点孤立的生态系统:为 Zope 编写的代码在 Zope 之外不太可用,反之亦然。 为了解决这个问题,Zope 3 的努力开始了。 Zope 3 将 Zope 重新设计为一组更干净的隔离组件。 这项工作是在 WSGI 标准出现之前就开始的,但是 Repoze 项目提供了对 Zope 3 的 WSGI 支持。 Zope 组件在其背后有多年的生产使用,Zope 3 项目让更广泛的 Python 社区可以访问这些组件。 甚至还有一个基于 Zope 组件的单独框架:Grok。
Zope 也是 Plone 内容管理系统使用的基础架构,该系统是可用的最强大和最受欢迎的内容管理系统之一。