Webアプリケーション

高速プロトタイプと大きなプロジェクトの両方に対応した強力なスクリプト言語として、PythonはWebアプリケーション開発に広く使用されています。

コンテキスト

WSGI

Webサーバーゲートウェイインターフェイス(略して “WSGI” )は、WebサーバーとPython Webアプリケーションフレームワークの間の標準インターフェイスです。 WSGI準拠のWebサーバ をWebサーバやPythonのWebフレームワークとの間に動作し、通信を標準化することで、WSGIはいずれにも展開することができる携帯用のPythonのWebコードを記述することが可能となります。 WSGIは、pep:3333 に記載されています。

フレームワーク

大まかに言えば、Webフレームワークは、一連のライブラリとメインハンドラで構成され、その中にWebアプリケーション(つまり、インタラクティブな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モジュールを書くのと似ていますが、いくつかの関数にはルートが付けられています。 それは本当に美しいです。

おそらく必要なものをすべて提供することを目指すのではなく、URLルーティング、リクエストとレスポンスオブジェクト、テンプレートなど、Webアプリケーションフレームワークの中で最も一般的に使用されるコアコンポーネントを実装します。

Flaskを使用している場合は、アプリケーションの他のコンポーネントがあればそれを選択する必要があります。 たとえば、データベースへのアクセスやフォームの生成と検証は、Flaskの組み込み関数ではありません。

多くのWebアプリケーションにはこれらの機能が必要ないので、これは素晴らしいことです。 そういう人には、あなたのニーズに合った Extensions がたくさんあります。 または、あなたが望む任意のライブラリを簡単に使用できます。

Flaskは、Djangoには適していないPython Webアプリケーションのデフォルトの選択です。

Tornado

Tornado は独自のイベントループを持つPython用の非同期Webフレームワークです。これにより、例えばWebSocketをネイティブにサポートすることができます。よく書かれたTornadoのアプリケーションは、優れた性能特性を持つことが知られています。

必要があると思わない限り、Tornadoの使用をお勧めしません。

Pyramid

Pyramid は、モジュール性に重点を置いた非常に柔軟なフレームワークです。 少数のライブラリ (“電池”) が内蔵されており、ユーザが基本機能を拡張するように促します。

DjangoやFlaskとは異なり、Pyramidには大きなユーザーベースはありません。 これは有能なフレームワークですが、今日の新しいPython Webアプリケーションにとってはあまり一般的ではありません。

Web Servers

Nginx

Nginx (“engine-x”と発音) は、HTTP、SMTPなどのプロトコル用のWebサーバーとリバースプロキシです。 高性能で、比較的シンプルで、多くのアプリケーションサーバー(WSGIサーバーなど)との互換性があることが知られています。 また、ロードバランシング、基本認証、ストリーミングなどの便利な機能も含まれています。 高負荷のウェブサイトに対応するように設計されたNginxは、徐々に普及しています。

WSGI Servers

スタンドアロンのWSGIサーバーは、通常、従来のWebサーバーよりも少ないリソースを使用し、最高のパフォーマンス [3] を提供します。

Gunicorn

Gunicorn (Green Unicorn) はPythonアプリケーションを提供するために使われる純粋なPythonのWSGIサーバーです。 他のPython Webサーバーとは異なり、思慮深いユーザーインターフェイスがあり、使いやすく構成が簡単です。

Gunicornは、構成に対して正気で合理的なデフォルトを持っています。 しかし、uWSGIのような他のサーバーは、大幅にカスタマイズ可能であるため、効果的に使用するのがはるかに困難です。

Gunicornは今日の新しいPython Webアプリケーションの推奨選択肢です。

Waitress

Waitress は、”非常に許容可能なパフォーマンス” を主張する純粋なpython WSGIサーバーです。 そのドキュメントはあまり詳細ではありませんが、Gunicornにはない優れた機能(HTTPリクエストバッファリングなど)があります。

WaitressはPython Web開発コミュニティで人気を博しています。

uWSGI

uWSGI は、ホスティングサービスを構築するための完全なスタックです。 プロセス管理、プロセス監視、およびその他の機能に加えて、uWSGIは、PythonやWSGIなど、さまざまなプログラミング言語とプロトコルのアプリケーションサーバーとして機能します。 uWSGIは、スタンドアロンのWebルーターとして実行することも、完全なWebサーバー(NginxやApacheなど)の背後で実行することもできます。 後者の場合、WebサーバーはuWSGIとアプリケーションの操作を uwsgi protocol で設定できます。 uWSGIのWebサーバーサポートにより、Pythonを動的に構成し、環境変数を渡し、さらにチューニングすることができます。 詳細については、 uWSGIマジック変数 を参照してください。

なぜ必要なのか分からない限り、私はuWSGIの使用をお勧めしません。

サーバーのベストプラクティス

現在ホストされているPythonアプリケーションの大部分は、 nginx のような軽量のWebサーバーの後ろにある Gunicorn のようなWSGIサーバーでホストされています。

WSGIサーバーはPythonアプリケーションを処理しますが、Webサーバーは静的ファイルサービス、要求ルーティング、DDoS保護、基本認証など、より適切なタスクを処理します。

ホスティング

PaaS(Platform-as-a-Service)は、Webアプリケーションのインフラストラクチャ、ルーティング、およびスケーリングを抽象化して管理するクラウドコンピューティングインフラストラクチャの一種です。 PaaSを使用する場合、アプリケーション開発者はデプロイの詳細を意識する必要はなく、アプリケーションコードの作成に専念することができます。

Heroku

Heroku はPython 2.7-3.5アプリケーションのための一流のサポートを提供します。

Herokuは、あらゆる種類のPython Webアプリケーション、サーバー、およびフレームワークをサポートしています。 アプリケーションは無料でHerokuで開発することができます。 アプリケーションの本稼働準備が整ったら、趣味やプロフェッショナルアプリケーションにアップグレードできます。

Herokuは、PythonとHerokuを使用した 詳細な記事 と、 ステップバイステップの手順 最初のアプリケーションの設定方法について説明します。

Herokuは、今日のPython Webアプリケーションの展開に推奨されるPaaSです。

Eldarion

Eldarion (正式にGondorとして知られています) は、Kubernetes、CoreOS、およびDockerによるPaaSです。彼らはどんなWSGIアプリケーションもサポートしており、 Django projects の導入に関するガイドを持っています。

テンプレート

ほとんどのWSGIアプリケーションは、HTMLや他のマークアップ言語でコンテンツを提供するためにHTTP要求に応答しています。 Pythonから直接テキストコンテンツを生成するのではなく、懸念を分離するという概念は、テンプレートを使用するように私たちに助言します。テンプレートエンジンは、不必要な繰り返しを避けるための階層と包含のシステムを備えたテンプレートファイル群を管理し、実際のコンテンツのレンダリング(生成)を担当し、テンプレートの静的コンテンツをアプリケーションによって生成された動的コンテンツです。

テンプレートファイルはデザイナーやフロントエンドの開発者によって書き込まれることがあるため、増えていく複雑さに対応することは困難です。

一般的な良い方法は、動的コンテンツをテンプレートエンジンやテンプレート自体に渡すアプリケーションの部分に適用されます。

  • テンプレートファイルには、テンプレートのレンダリングに必要な動的コンテンツのみが渡されます。 「念のため」に追加のコンテンツを渡すような誘惑を避けてください。未使用の変数を後で削除するよりも必要なときに不足している変数を追加する方が簡単です。
  • 多くのテンプレートエンジンでは、テンプレート自体に複雑なステートメントや割り当てが可能であり、多くの場合、テンプレートでPythonコードを評価できるものが多数あります。 この利便性は、制御されていない複雑さの増加につながり、しばしばバグを見つけにくくします。
  • JavaScriptテンプレートとHTMLテンプレートを混在させる必要があることがよくあります。 この設計に対する単純なアプローチは、HTMLテンプレートがいくつかの可変コンテンツをJavaScriptコードに渡す部分を分離することです。

Jinja2

Jinja2 は非常によく評価されているテンプレートエンジンです。

これは、テキストベースのテンプレート言語を使用するので、HTMLだけでなく、あらゆるタイプのマークアップを生成するために使用できます。 これは、フィルタ、タグ、テスト、およびグローバルのカスタマイズを可能にします。 これは、Djangoのテンプレートシステムよりも多くの改善点があります。

ここでJinja2の重要なHTMLタグ:

{# This is a comment #}

{# The next tag is a variable output: #}
{{title}}

{# Tag for a block, can be replaced through inheritance with other html code #}
{% block head %}
<h1>This is the head!</h1>
{% endblock %}

{# Output of an array as an iteration #}
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}

次の一覧は、Tornado Webサーバーと組み合わせたWebサイトの例です。 Tornadoはそれほど複雑ではありません。

# import Jinja2
from jinja2 import Environment, FileSystemLoader

# import Tornado
import tornado.ioloop
import tornado.web

# Load template file templates/site.html
TEMPLATE_FILE = "site.html"
templateLoader = FileSystemLoader( searchpath="templates/" )
templateEnv = Environment( loader=templateLoader )
template = templateEnv.get_template(TEMPLATE_FILE)

# List for famous movie rendering
movie_list = [[1,"The Hitchhiker's Guide to the Galaxy"],[2,"Back to future"],[3,"Matrix"]]

# template.render() returns a string which contains the rendered html
html_output = template.render(list=movie_list,
                        title="Here is my favorite movie list")

# Handler for main page
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # Returns rendered template string to the browser request
        self.write(html_output)

# Assign handler to the server root  (127.0.0.1:PORT/)
application = tornado.web.Application([
    (r"/", MainHandler),
])
PORT=8884
if __name__ == "__main__":
    # Setup the server
    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}} - My Webpage</title>
</head>
<body>
<div id="content">
    {# In the next line the content from the site.html template will be added #}
    {% block content %}{% endblock %}
</div>
<div id="footer">
    {% block footer %}
    &copy; Copyright 2013 by <a href="http://domain.invalid/">you</a>.
    {% endblock %}
</div>
</body>

次のリストは、 base.html を拡張したPythonアプリケーションにロードされたサイトページ (site.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テンプレートエンジンの Template Attribute Language (TAL) の実装です。 TAL式構文 (TALES)マクロ展開TAL (Metal) シンタックス。

ChameleonはPython 2.5以降(3.xやpypyを含む)で利用可能で、 Pyramid Framework で一般的に使用されています。

ページテンプレートは、ドキュメント構造内に特別な要素属性とテキストマークアップを追加します。 単純な言語構造のセットを使用して、文書の流れ、要素の繰り返し、テキストの置換と翻訳を制御します。 属性ベースの構文のため、未レンダリングページテンプレートは有効な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コミュニティで尊敬されています。

References

[1]The mod_python project is now officially dead
[2]mod_wsgi vs mod_python
[3]Benchmark of Python WSGI Servers