Menu

6.2. Web 应用 & 框架

file

Python 作为一门强大的脚本语言,能够适应快速原型和较大项目的制作,它被广泛用于 web 应用程序的开发中。

Context

WSGI

Web 服务网关接口 (简称为 "WSGI" ) 是一种在 Web 服务器和 Python Web 应用程序框架之间的标准接口。 通过标准化 Web 服务器和Python web 应用程序框架之间的行为和通信,WSGI 使得编写可移植的的 Python web 代码变为可能,使其能够部署在任何符合 WSGI 的 web 服务。WSGI 记录在 PEP 3333.

框架

广义地说,Web 框架包含一系列库和一个主要的处理器 (handler),这样你就能够构建自己的代码来实现Web应用 (比如说一个交互式的网站)。大多数 web 框架包含模式和工具,至少实现以下功能:

URL 路由

将输入的 HTTP 请求匹配到特定的 Python 代码用来调用

请求和响应对象

封装来自或发送给用户浏览器的信息

模板引擎

能够将实现应用的 Python 代码逻辑和其要产生输出的 HTML (或其他的) 分离开

Web 服务开发

在开发机上运行 HTTP 服务器,从而快速开发;当文件更新时自动更新服务端代码。

Django

Django 是一个功能齐备的 web 应用框架,它是创建面向内容网站的极佳选择。 通过提供众多工具和模式, Django 使得快速构建复杂的、有数据库支持的web应用成为可能, 同时鼓励使用它作为编写代码的最佳实践。

Django 拥有非常庞大和活跃的社区,许多预构建的 可重用模块 可以原样合并到新工程中,或者定制成符合需求的样子。

在 美国欧洲, 澳大利亚 都会有年度 Django 会议。

如今大部分新的 Python web 应用都是用 Django 构建的。

Flask

Flask 是一个针对 Python 的“微型框架”,它是构建更小应用、API 和 web 服务的极佳选择。

使用Flask构建应用,它和写标准 Python 模块很相似,除了一些函数附上路由。它真的很赞。

Flask 不会提供一切你可能需要的内容,而是实现了 web 应用框架中最常用的核心组件,比如说 URL 路由、请求和响应对象和模板等。

作为 Flask 的用户,在你的应用中由你来选择其他你可能用到的组件。比如说数据库访问或者表单生成和验证就不是 Flask 内置的功能。

这样挺好的,因为很多 web 应用并不需要这些特性。 对于那些需要的,有许多可用的 扩展 或许符合你的要求。

Tornado

Tornado 是一个面向 Python 的异步 web 框架,它有自己的事件。比如,可以原生地支持 WebSockets。可以编写良好的 Tornado 应用并具有卓越的性能特性。

我并不建议使用 Tornado,除非你认为自己需要它。

Pyramid

Pyramid 是一个非常灵活的框架,重点关注模块化。 它内置少量库 (“电池”) ,并鼓励用户扩展其基本功能。

Pyramid 不像 Django 和 Flask,并没有庞大的用户基数。它是一个有能力的框架,但如今新的 Python web 应用程序并没有十分青睐它。

Web 服务端

Nginx

Nginx (发音为"engine-x") 是一个 web 服务器,并且是 HTTP 、SMTP 和其他协议的反向代理。 它由其高性能、相对简洁以及对众多应用服务器 (比如 WSGI 服务器) 兼容而著名。它也拥有便利的特性, 比如负载均衡、基本的认证、流等。Nginx 被设计为承载高负载的网站,并逐渐变得广为流行。

WSGI 服务器

独立 WSGI 服务器相比传统 web 服务器,使用更少的资源,并提供最高的性能 [3]

Gunicorn

Gunicorn (Green Unicorn,绿色独角兽) 是一个纯 Python WSGI 服务器,用来支持 Python 应用。不像其他 Python web 服务器,它有周全的用户界面,十分易于使用和配置。

Gunicorn 具有合理的默认配置。 然而,其他一些像 uWSGI 这样的服务器相较而言过于可定制化,因此更加难以高效使用。

Gunicorn 是如今新 Python web 应用程序的推荐选择。

Waitress

Waitress 是一个纯 Python WSGI 服务器,声称具备“非常高效的性能”。 它的文档不是很详细,但它确实提供了一些很好的而 Gunicorn 没有的功能(例如 HTTP 请求缓冲)。

Waitress 在 Python Web 开发社区中越来越受欢迎。

uWSGI

uWSGI 用来构建全栈式的主机服务。除了进程管理、进程监控和其他功能外, uWSGI 也能作为一个应用服务器,适用于多种编程语言和协议 - 包括 Python 和 WSIG。 uWSGI 既能当作独立的 web 路由器来运行,也能运行在一个完整 web 服务器(比如 Nginx 或 Apache )之后。 对于后者,web 服务器可以基于 uwsgi 协议 配置 uWSGI 和应用的操作。uWSGI 的 web 服务器支持允许动态配置 Python 、传递环境变量以及进一步优化。 要看更多细节,请看 uWSGI 的魔法变量.

我并不建议使用 uWSGI ,除非你认为自己需要它。

服务端最佳实践

承载 Python 应用的主体托管于 WSGI 服务器,比如 Gunicorn,或者直接或间接的在轻量级 web 服务器,比如 nginx 之后。

WSGI 服务器为 Python 应用服务,它能更好的处理诸如静态文件服务、请求路由、DDoS 保护和基本认证的任务。

Hosting

平台即服务 (PaaS) 是一种云计算基础设施类型,抽象和管理基础设施、路由和网络应用的扩展。 使用 PaaS 时,应用开发者只需关注编写应用代码,而无须关心配置细节。

Heroku

Heroku 为 Python 2.7-3.5 应用程序提供一流的支持。

Heroku 支持所有类型的 Python web 应用、服务器和框架。在 Heroku 上可以免费开发应用程序。一旦您的应用程序准备好面向生产环境,您可以升级到 Hobby 或专业应用。

Heroku 维护了使用 Python 和 Heroku 交互的 详细文档, 同时也有 手把手指导 来告诉你如何建立第一个应用。

Heroku 是部署 Python Web 应用程序推荐的 PaaS。

Eldarion

Eldarion (被称为 Gondor ) 是由 Kubernetes、CoreOS 和 Docker 提供的 PaaS。它们支持任意 WSGI 应用程序,并提供了部署 Django 项目 的指南。

模板

大多数 WSGI 应用程序的服务内容是以 HTML 或其他标记语言响应 HTTP 请求。而不是直接从 Python 生成文本内容,建议我们使用模板来关注分离的概念。模板引擎以系统分层和包含来管理一系列模板文件,以避免不必要的重复,并负责渲染(生成)实际内容,用应用程序生成的动态内容填充模板的静态内容。

由于模板文件有时是由设计者或前端开发人员编写的,因此很难处理日益复杂的问题。

程序在这个环节上的一些通用的良好实践是给模板引擎或者给模板本身传递动态内容。

  • 模板文件应该仅接收渲染所必须的动态内容。避免向模板传递额外的内容仅仅是为了『以防万一』:毕竟日后朝模板中添加缺失的变量比删除那些看起来没有用到的变量要简单得多。
  • 许多模板引擎允许在模板中使用复杂的语句,以及在模板中执行 Python 代码。这个便利之处可能导致复杂度不可控的增长,也会使得 bug 难以发现。
  • 在模板中混合使用 JavaScript 与 HTML 代码是家常便饭。对此的一个明智做法是把 HTML 向 JavaScript 传递变量的那部分内容隔离开来。

Jinja2

Jinja2 是一个非常受欢迎的模板引擎。

它使用基于文本的模板语言,因此可以用来生成任何类型的标记,而不仅仅是 HTML。它允许定制过滤器、标签、测试和全局变量。它对 Django 的模板系统有许多改进。

这里有一些在 Jinja2 中重要的HTML标记:

{# 这是注释 #}

{# 下一个标签是一个变量输出: #}
{{title}}

{# 一个块标记,可以通过继承其他 HTML 代码来替换 #}
{% block head %}
<h1>这是头部!</h1>
{% endblock %}

{# 数组的迭代输出 #}
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}

下一个列表是一个和 Tornado web 服务器结合的 web 站点案例。Tornado 使用起来不是很复杂。

# 导入 Jinja2
from jinja2 import Environment, FileSystemLoader

# 导入 Tornado
import tornado.ioloop
import tornado.web

# 加载模板文件 templates/site.html
TEMPLATE_FILE = "site.html"
templateLoader = FileSystemLoader( searchpath="templates/" )
templateEnv = Environment( loader=templateLoader )
template = templateEnv.get_template(TEMPLATE_FILE)

# 著名电影列表
movie_list = [[1,"The Hitchhiker's Guide to the Galaxy"],[2,"Back to future"],[3,"Matrix"]]

# template.render() 返回一个包含渲染后 HTML 的字符串
html_output = template.render(list=movie_list,
                        title="Here is my favorite movie list")

# 主页处理程序
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # 返回浏览器请求的渲染后的模板字符串
        self.write(html_output)

# 将处理程序分配给服务器 root(127.0.0.1:PORT/)
application = tornado.web.Application([
    (r"/", MainHandler),
])
PORT=8884
if __name__ == "__main__":
    # 配置服务器
    application.listen(PORT)
    tornado.ioloop.IOLoop.instance().start()

base.html 文件可以用作所有站点页面的基础,例如在内容块中实现的站点页面。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{{title}} - 我的 Web 页面</title>
</head>
<body>
<div id="content">
    {# 在下一行中,将添加 site.html 模板的内容 #}
    {% block content %}{% endblock %}
</div>
<div id="footer">
    {% block footer %}
    © Copyright 2013 by <a href="http://domain.invalid/">you</a>.
    {% endblock %}
</div>
</body>

下一个列表是我们在 Python 应用程序中加载的站点页面(site.html),它扩展了 base.html。在 base.html 页面中,内容块被自动设置为相应的块。

{% extends "base.html" %}
{% block content %}
    <p class="important">
    <div id="content">
        <h2>{{title}}</h2>
        <p>{{ list_title }}</p>
        <ul>
             {% for item in list %}
             <li>{{ item[0]}} :  {{ item[1]}}</li>
             {% endfor %}
        </ul>
    </div>
    </p>
{% endblock %}

Jinja2 是新 Python Web 应用程序的推荐模板库。

Chameleon

Chameleon 是一个对 HTML/XML 模板引擎的 模板属性语言 (TAL), TAL 表达式语法 (TALES),以及 宏表达式 TAL (Metal) 语法的实现。

Chameleon 在 Python 2.5 及更高版本(包括 3.x 和 pypy)中可用,并且被 Pyramid 框架 使用。

页面模板在文档结构中添加特殊元素属性和文本标记。使用一套语言结构,你就控制了文档流,元素的重复,文本替换以及翻译。由于是基于属性的语法,所以那些没有被渲染的页面模板是合法的 HTML 代码,能够在浏览器中直接浏览,甚至可以在所见即所得(WYSIWYG) 编辑器中编辑。这可以实现与设计人员的往返协作,并且可以更轻松地在浏览器中对静态文件进行原型设计

基本的 TAL 语言简单到通过下面的例子就足以掌握:

<html>
  <body>
  <h1>Hello, <span tal:replace="context.name">World</span>!</h1>
    <table>
      <tr tal:repeat="row 'apple', 'banana', 'pineapple'">
        <td tal:repeat="col 'juice', 'muffin', 'pie'">
           <span tal:replace="row.capitalize()" /> <span tal:replace="col" />
        </td>
      </tr>
    </table>
  </body>
</html>

如果对模板的合法性要求没那么严格,那么 <span tal:replace="expression" /> 标签是个很常见的写法。你也可以使用更简洁,可读性更高的 ${expression} 写法,就像下面这样:

<html>
  <body>
    <h1>Hello, ${world}!</h1>
    <table>
      <tr tal:repeat="row 'apple', 'banana', 'pineapple'">
        <td tal:repeat="col 'juice', 'muffin', 'pie'">
           ${row.capitalize()} ${col}
        </td>
      </tr>
    </table>
  </body>
</html>

但要记住, <span tal:replace="expression">Default Text</span> 这个语法也是允许在未渲染的模板中出现默认内容的。

尽管出身于 Pyramid 的世界,但是 Chameleon 并没有被广泛使用。

Mako

Mako 是一个编译成 Python 以获得最大性能的模板语言。它的语法和 api 是借鉴自其它模板语言的最好部分,如 Django 和 Jinja2 模板。它是 Pylons and Pyramid web 框架包含的默认模板语言。

一个 Mako 模板的实例如下:

<%inherit file="base.html"/>
<%
    rows = [[v for v in range(0,10)] for row in range(0,10)]
%>
<table>
    % for row in rows:
        ${makerow(row)}
    % endfor
</table>

<%def name="makerow(row)">
    <tr>
    % for name in row:
        <td>${name}</td>\
    % endfor
    </tr>
</%def>

渲染一个非常基础的模板,你可以像下面这样做:

from mako.template import Template
print(Template("hello ${data}!").render(data="world"))

Mako 在 Python web 社区中备受推崇。

参考

[1] The mod_python 项目现在正是死掉
[2] mod_wsgi vs mod_python
[3] Python WSGI 服务器基准测试

本文章首发在 PythonCaff
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~