ラベル Linux の投稿を表示しています。 すべての投稿を表示
ラベル Linux の投稿を表示しています。 すべての投稿を表示

2013年2月4日月曜日

Bottleのプラグインの動作方法:基本


プラグインの動作方法:基本

プラグインAPIは、デコレータの概念に基づいています。簡潔に言えば、プラグインは、アプリケーションのすべての単一のルートコールバックに適用されるデコレータです。
もちろん、これは単に単純化したものです。プラグインは、単なる装飾ルートのコールバックより多くを行うことができますが、それは良い出発点です。貸し付けは、いくつかのコードを見てみましょう:
from bottle import response, install
import time

def stopwatch(callback):
    def wrapper(*args, **kwargs):
        start = time.time()
        body = callback(*args, **kwargs)
        end = time.time()
        response.headers['X-Exec-Time'] = str(end - start)
        return body
    return wrapper

bottle.install(stopwatch)
このプラグインはリクエストごとに実行時間を測定し、応答に適切なX-EXECタイムヘッダーを追加します。あなたが見ることができるように、プラグインがラッパーを返し、ラッパーは、再帰的に元のコールバックを呼び出します。これは、デコレータは、通常の動作方法です。
最後の行は、デフォルトのアプリケーションにプラグインをインストールするには、ボトルに指示します。これは、プラグインは自動的にそのアプリケーションのすべてのルートに適用されるようになります。言い換えれば、ストップウォッチ()は、各ルートのコールバックに対して一度呼び出され、戻り値は、元のコールバックの代わりとして使用されています。
プラグインは、ルートが初めて要求されるとすぐに、つまりオンデマンドで適用されます。このマルチスレッド環境で正しく動作させるには、プラグインはスレッド·セーフでなければなりません。これはほとんどの時間の問題ではありませんが、それに留意してください。
すべてのプラグインがルートに適用されると、ラップされたコールバックは、キャッシュされ、後続の要求は、直接キャッシュされたバージョンによって処理されます。これは、プラグインは通常、特定のルートに一度だけ適用されることを意味します。そのキャッシュは、しかし、たびにインストールされているプラ​​グインの変更のリストがクリアされます。あなたのプラグインは、複数回同じルートを飾ることができるはずです。
デコレータのAPIは非常にかかわらず、制限されています。あなたがデコレートされたルートまたは、関連付けられたアプリケーションオブジェクトについて何を知っていて、効率的にすべてのルート間で共有されるデータを格納する方法がありませんありません。しかし、恐怖はありません!プラグインは、単にデコレータ関数に限定されるものではない。ボトルは、それが呼び出し可能であるか、または拡張APIを実装している限り、プラグインとして何かを受け入れます。このAPIは、以下に説明すると、処理全体の制御の多くを提供しています。

プラグインAPI

プラグインは、実際のクラス(あなたがボトルからそれをインポートすることはできません)が、プラグインが実装すると予想されているインタフェースではありません。ボトルは、プラグインとして任意の型の任意のオブジェクトを受け入れる限り、それは以下のAPIに準拠している。
class Plugin(object)
プラグインは呼び出し可能であるかは、apply()を実装する必要があります。
apply()適用されるが定義されている場合、それは常に直接プラグインを呼び出すことが優先されます。 他のすべてのメソッドや属性はオプションです。
name
両方Bottle.uninstall()とBottle.routeのスキップ·パラメータは、()プラグインまたはプラグインタイプを参照するために名前の文字列を受け入れます。これは、name属性を持っているプラ​​グインに対してのみ機能します。
api
プラグインAPIは、まだ進化しています。この整数型の属性は、どちらのバージョンを使用するボトルを指示します。最初のバージョンにそれが欠落している場合は、ボトルをデフォルトとします。現在のバージョンは2です。詳細については、プラグインAPIの変更を参照してください。
setup(self, app)
とすぐにプラグインがアプリケーションにインストールされていると呼ばれる(Bottle.install()を参照)。唯一のパラメータは、関連付けられたアプリケーションオブジェクトです。
call(self, callback)
限り定義されていません)(適用されるように、プラグイン自体は、デコレータとして使用され、各ルートのコールバックに直接適用されます。唯一のパラメータは、飾るためのコールバックです。このメソッドによって返される任意の元のコールに置き換えられます。与えられたコールバック関数をラップまたは交換する必要はありません場合は、単に変更されていないコールバックパラメータを返します。
apply(self, callback, route)¶
定義されている場合、このメソッドはルートのコールバックを飾るためにcallを通じて()に有利に使用されています。追加ルートパラメータは、ルートのインスタンスであり、そのルートのメタ情報とコンテキストの多くを提供しています。詳細については、ルートコンテキストを参照してください。
close(self)¶
プラグインがアンインストールされるか、またはアプリケーションが閉じられる直前に呼び出されます。
(Bottle.uninstall()またはBottle.close()を参照してください)​​
Plugin.setup()とPlugin.close()の両方がBottle.route()デコレータを経由して、だけのアプリケーションにインストールされているプラ​​グインのルートに直接適用されているプラ​​グインを呼び出されません。

プラグインAPIの変更

プラグインAPIはまだ発展途上とルートコンテキストの辞書を持つ特定の問題に対処するためにボトル0.10で変更されます。 0.9プラグインとの下位互換性を確保するために、我々は、どのAPIが使用するように瓶を指示するオプションのPlugin.api属性を追加しました。 APIの違いはここに要約されています。
ボトル0.9 API 1(Plugin.api存在しない)
0.9のドキュメントで説明するようにオリジナルのプラグインAPI。
ボトル0.10 API 2(Plugin.apiは2に等しい)
Plugin.apply()メソッドのcontextパラメータは現在、代わりにコンテキスト辞書のルートのインスタンスです。

ルートコンテキスト

Plugin.applyに渡されたルート·インスタンスは、()関連付けられたルートに関する詳細な情報を提供しています。最も重要な属性は以下にまとめています:

属性の説明

アプリは、アプリケーションオブジェクトは、このルートは次のようにインストールされています。
AttributeDescription
appThe application object this route is installed to.
ruleThe rule string (e.g. /wiki/:page).
methodThe HTTP method as a string (e.g. GET).
callbackThe original callback with no plugins applied. Useful for introspection.
nameThe name of the route (if specified) or None.
pluginsA list of route-specific plugins. These are applied in addition to application-wide plugins. (see Bottle.route()).
skiplistA list of plugins to not apply to this route (again, see Bottle.route()).
configAdditional keyword arguments passed to the Bottle.route() decorator are stored in this dictionary. Used for route-specific configuration and meta-data.
プラグインについては、Route.configは、おそらく最も重要な属性です。この辞書は、ルートに対してローカルであることを心に留めておくが、すべてのプラグイン間で共有されます。それは常にあなたのプラグインが設定ディクショナリ内の別の名前空間に格納し、コンフィギュレーションの多くを必要とする場合、一意の接頭辞を追加したりすることをお勧めします。これは、プラグイン間での名前の衝突を回避するのに役立ちます。

Routeオブジェクトを変更する

いくつかのルートの属性は可変ですが、変更が他のプラグイン上で望ましくない影響があるかもしれません。それは猿パッチを適用する可能性が最も高い代わりに、有用なエラーメッセージを提供し、ユーザーが問題を解決させるの壊れたルートは悪い考えです。
まれに、しかし、それはこのルールを破ることが正当かもしれません。あなたはルートインスタンスに変更を加えた後、例外としてRouteResetが発生します。これは、キャッシュから現在のルートを削除し、すべてのプラグインが再適用されるようになります。ルータは、しかし、更新されません。ルールまたはメソッドの値の変更は、ルータに影響を与えませんが、プラグインだけで。ただし、これは将来変更されるかもしれません。

ランタイムの最適化

すべてのプラグインがルートに適用されると、ラップされたルートのコールバックは、後続の要求をスピードアップするためにキャッシュされます。プラグインの動作は設定に依存し、実行時にその設定を変更することができるようにしたい場合は、要求ごとに設定を読む必要があります。十分に簡単です。
パフォーマンス上の理由から、しかし、それは、現在のニーズに基づいて、さまざまなラッパーを選択して、クロージャで動作する、または実行時にプラグインを有効または無効にする価値があるかもしれません。の例として、組み込みHooksPluginてみましょう。ないフックがインストールされていない場合、プラグインが影響を受けるすべてのルートから自身を削除し、virtaullyないオーバーヘッドがありません。できるだけ早くあなたが最初のフックをインストールすると、プラグイン自体を活性化し、再び有効になります。
これを実現するには、コールバックのキャッシュを制御する必要があります。Route.reset()が一度にアプリケーションのすべてのルートのすべてのキャッシュをクリアし、単一のルートとBottle.reset()のキャッシュをクリアします。それが最初に要求されたかのように次のリクエストに応じて、すべてのプラグインは、ルートに再適用されます。
原因のルートコールバック内から呼び出された場合、両方のメソッドは、現在の要求には影響しません。現在の要求の再起動を強制するには、例外としてRouteResetが発生します。

プラグインの例:SQLitePlugin

このプラグインは、ラップされたコールバックに追加のキーワード引数としてsqlite3のデータベース接続ハンドルを提供していますが、コールバックは、それを期待している場合のみです。されていない場合、ルートは無視され、オーバーヘッドが追加されません。ラッパーは、戻り値に影響を与えますが、適切にプラグインに関連する例外を処理していません。 Plugin.setup()が競合しているプラ​​グイン用のアプリケーションを検索して検査するために使用されています。
import sqlite3
import inspect

class SQLitePlugin(object):
    ''' This plugin passes an sqlite3 database handle to route callbacks
    that accept a `db` keyword argument. If a callback does not expect
    such a parameter, no connection is made. You can override the database
    settings on a per-route basis. '''

    name = 'sqlite'
    api = 2

    def __init__(self, dbfile=':memory:', autocommit=True, dictrows=True,
                 keyword='db'):
         self.dbfile = dbfile
         self.autocommit = autocommit
         self.dictrows = dictrows
         self.keyword = keyword

    def setup(self, app):
        ''' Make sure that other installed plugins don't affect the same
            keyword argument.'''
        for other in app.plugins:
            if not isinstance(other, SQLitePlugin): continue
            if other.keyword == self.keyword:
                raise PluginError("Found another sqlite plugin with "\
                "conflicting settings (non-unique keyword).")

    def apply(self, callback, context):
        # Override global configuration with route-specific values.
        conf = context.config.get('sqlite') or {}
        dbfile = conf.get('dbfile', self.dbfile)
        autocommit = conf.get('autocommit', self.autocommit)
        dictrows = conf.get('dictrows', self.dictrows)
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'db' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context.callback)[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Connect to the database
            db = sqlite3.connect(dbfile)
            # This enables column access by name: row['column_name']
            if dictrows: db.row_factory = sqlite3.Row
            # Add the connection handle as a keyword argument.
            kwargs[keyword] = db

            try:
                rv = callback(*args, **kwargs)
                if autocommit: db.commit()
            except sqlite3.IntegrityError, e:
                db.rollback()
                raise HTTPError(500, "Database Error", e)
            finally:
                db.close()
            return rv

        # Replace the route callback with the wrapped one.
        return wrapper
このプラグインは、実際に役に立つとボトルにバンドルされているバージョンと非常に似ています。コー​​ド未満の60行は悪くない、あなたは思いませんか?ここで使用例は、次のとおりです。
sqlite = SQLitePlugin(dbfile='/tmp/test.db')
bottle.install(sqlite)

@route('/show/:page')
def show(page, db):
    row = db.execute('SELECT * from pages where name=?', page).fetchone()
    if row:
        return template('showpage', page=row)
    return HTTPError(404, "Page not found")

@route('/static/:fname#.*#')
def static(fname):
    return static_file(fname, root='/some/path')

@route('/admin/set/:db#[a-zA-Z]+#', skip=[sqlite])
def change_dbfile(db):
    sqlite.dbfile = '/tmp/%s.db' % db
    return "Switched DB to %s.db" % db
最初のルートは、データベース接続を必要とdbのキーワード引数を要求することにより、ハンドルを作成するためのプラグインに指示します。 2つ目のルートは、データベースを必要としないので、プラグインによって無視されます。第三のルートは 'db'とキーワード引数を期待していますが、明示的にsqliteのプラグインをスキップします。この方法では引数はプラグインによって無効にしても同じ名前のURL引数の値が含​​まれていません。

Bottleのチュートリアル:To-Do - リスト·アプリケーション



チュートリアル:To-Do - リスト·アプリケーション

注意
このチュートリアルでは、progessの作品であるとnoisefloorによって書かれた。
このチュートリアルでは、Bottle-WSGIフレームワークについて、簡単に紹介をする必要があります。このチュートリアルでは、ボトルWSGIフレームワークを簡単に紹介を与える必要があります。主な目標は、ボトルを使用してプロジェクトを作成するには、このチュートリアルを読んだ後、できるようにすることです。 このドキュメント内で、すべての機能は、説明されますが、少なくともBottleのテンプレート能力を利用したフォーマット出力の取扱いと、主要なルーティングとGET/POSTパラメータ。
ここで内容を理解するために、WSGIの基本的な知識を持っている必要はありません。Bollteは、とにかくユーザーからWSGIを遠ざけるしようとしています。あなたは、Pythonプログラミング言語を正しく理解しておく必要があります。 また、チュートリアルの取得およびSQL databseにデータを格納に使用される例ですので、SQLに関する基本的な考え方は役立ちますが、Bollteの概念を理解する為には必要ありません。ここで、SQLiteは使用されています。 ブラウザに送信されるBollteの出力は、HTMLの助けを借りていくつかの例でフォーマットされています。 したがって、一般的なHTMLタグについての基本的な考え方は同様に役立ちます。
Bollteを導入するために、"in between" Pythonのコードは、フォーカスを維持するために、短くされています。 また、チュートリアル内のすべてのコードは、正常に動作しています. しかし、あなたは必ずしも例えば、 "in the wild" それを使用することはできません 公共のWebサーバー上の。 そのためには、あなたは、例えばを追加することができ,より多くのエラー処理、パスワードを使用してデータベースを保護するP-:

目標

このチュートリアルの最後に、我々は、シンプルなWebベースのToDoリストがあります。リストには、各項目のテキスト(最大100文字)と状態(閉じた場合は0、開いている1)が含まれています。 Webベースのユーザーインターフェイスを介して、開いているアイテムは、ビューすることができ、編集し、新しいアイテムを追加することができます。
開発中に、すべてのページはlocalhost上で利用できるようになりますが、後でその上には、Apacheのmod_wsgiを一緒に使用する方法など、"本物の"サーバ用のアプリケーションに適応する方法を表示されます。
Bollteには、テンプレートの助けを借りて、ルーティングとフォーマット出力を行います。リストの項目は、SQLiteデータベース内に格納されます。データベースの読み取りと書き込みはPythonコードによって行われます。

始める前に…

ボトルをインストールする

あなたがPython(バージョン2.5以上)の比較的新しいインストールされていると仮定して、あなただけのそれに加えてボトルをインストールする必要があります。ボトルは、Python自体よりも他の依存関係を持っていません。
手動でボトルをインストールするか、Pythonのeasy_installを使用することができ、次のいずれかeasy_installを

ボトルを

さらにソ​​フトウェアの必需品
我々はデータベースとしてSQLite3を使うとして、それがインストールされていることを確認してください。 Linuxシステムでは、ほとんどのディストリビューションではsqlite3デフォルトでインストールされています。 SQLiteは、同様にWindowsとMacOS Xのために利用可能で、sqlite3モジュールは、Python標準ライブラリの一部です。

SQLデータベースを作成します。

最初に、我々は後で使用するデータベースを作成する必要があります。これを行うには、プロジェクトディレクトリに次のスクリプトを保存およびPythonを使用して、それを実行します。あなたも、対話型インタプリタを使用することができます。
import sqlite3
con = sqlite3.connect('todo.db') # Warning: This file is created in the current directory
con.execute("CREATE TABLE todo (id INTEGER PRIMARY KEY, task char(100) NOT NULL, status bool NOT NULL)")
con.execute("INSERT INTO todo (task,status) VALUES ('Read A-byte-of-python to get a good introduction into Python',0)")
con.execute("INSERT INTO todo (task,status) VALUES ('Visit the Python website',1)")
con.execute("INSERT INTO todo (task,status) VALUES ('Test various editors for and check the syntax highlighting',1)")
con.execute("INSERT INTO todo (task,status) VALUES ('Choose your favorite WSGI-Framework',0)")
con.commit()
これは、データベースファイルのTODOと呼ばれるテーブルと3つの列idを持つtodo.db、タスク、およびステータスを生成します。 idは、行を参照するために後で使用される行ごとに、一意のIDです。列タスクは、タスクを説明するテキストを保持し、それは最大100文字の長さにすることができます。最後に、列のステータスはopen(値1)かクローズ(値0)としてタスクをマークするために使用されています。

Bottleを使用したWebベースのToDoリスト

今ではWebベースのアプリケーションを作成するために、Bottleを導入する必要がある。 routes:しかし、最初に、我々は、ボトルの基本的な概念に注目する必要があります。

routesを理解する

ページアドレスが呼び出されたときに、基本的には、ブラウザに表示され、各ページが動的に生成されます。したがって、静的なコンテンツはありません。サーバー上の特定のアドレス:これは、ボトル内の "routes"と呼ばれるものとまったく同じです。 "TODO"のルートに定義されている(Python)関数がある場合は、したがって、たとえば、ページhttp://localhost:8080/todoがブラウザから呼び出されたときに、Bottleには、コールとのチェックを “grabs” 。そうだとすれば、ボトルには、対応するPythonコードを実行し、その結果を返します。

最初のステップ - すべてのアイテムを表示

したがって、ルートの概念を理解した後に、まず1を作成することができます。目標は、ToDoリストから全ての項目を開いて表示する事です。
import sqlite3
from bottle import route, run

@route('/todo')
def todo_list():
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    c.execute("SELECT id, task FROM todo WHERE status LIKE '1'")
    result = c.fetchall()
    return str(result)

run()
ファイルと同じディレクトリに、好ましくは、コードのtodo.pyを保存todo.db. そうでなければ、sqlite3.connect()ステートメントでtodo.dbへのパスを追加する必要があります。
我々だけで何をしたかを見てみましょう: 私たちは、SQLiteデータベースにアクセスするためにsqlite3の必要なモジュールをインポートし、 Bottleから我々はroutesとrunをインポートしました。run()文は、単にBottleに含まれるWebサーバーを起動します。デフォルトでは、Webサーバーは、localhostのポート8080上のページを提供します。さらに、我々はBottleのルーティングの責任関数であるルートをインポートします。あなたが見ることができるように、我々は、データベースからの読み込み、数行のコードで、一つの関数todo_list()を定義しました。重要な点は、右のdef todo_list()ステートメントの前に、デコレータ文@route('/todo')です。これにより、我々はroot/todoには、この関数をバインドするので、毎回ブラウザがhttp://localhost:8080/todoを呼び出して、Bottleは、関数todo_list()の結果を返します。それは瓶の作品内のルーティング方法です。
実際には、関数に複数のルートにバインドすることができます。次のコードは、だから:
@route('/todo')
@route('/my_todo_list')
def todo_list():
    ...
あまりにも、正常に動作します。何が動作しませんと、1つ以上の関数に1つのルートをバインドすることです。
どのブラウザで表示されますと、このように、返されるreturn文で指定された値です。この例では、Bottleにはreturn文から文字列または文字列のリストを期待するようには、str()によって文字列に結果を変換する必要があります。しかし、ここでは、データベースクエリの結果は、Python DB APIで定義されている標準であるタプルのリストです。
今、少し上のスクリプトを理解した上で、それを実行し、結果自分自身を監視する時間です。 Linuxベース/Unixベースのシステム上のファイルtodo.pyを最初に実行する必要があることを覚えておいてください。その後、ちょうどのpython todo.pyを実行し、ブラウザでページhttp://localhost:8080/todoを呼び出します。スクリプトを書き込んでもミスを犯しません場合、出力は次のようになります
[(2, u'Visit the Python website'), (3, u'Test various editors for and check the syntax highlighting')]
もし、上記の表示なら - おめでとうございます!あなたは、ボトルの成功したユーザーです。もし、動作しなかった場合は、スクリプトにいくつかの変更を加える必要があります、その時にページを提供しているボトルを停止することを忘れないでください。別の方法としての改訂版がロードは提供されません。 実際に、それは、SQLクエリから返される生の結果ですので、出力結果を読むことは本当にエキサイティングでも良いものでもありません。そこで、次の手順で私たちはよりよい方法で出力をフォーマットします。しかし我々はそれを行う前に、私たちは私たちの作業がが容易になる方法があります。

デバッグとオートリロード

たぶん、あなたはすでにスクリプトが間違って、例えば、Bollteの中に、何かのブラウザに短いエラーメッセージを送信することに気づいたり、データベースへの接続が動作していなかったり。 デバッグの目的のために、それはより多くの細かい情報を得るために非常に便利は方法があります。 これは簡単にスクリプトに次のステートメントを追加することによって達成することができます:
from bottle import run, route, debug
...
#add this at the very end:
debug(True)
run()
"debug"を有効にすることで、通常のバグを見つけるための有用な情報が含まれているPythonインタプリタの完全なスタックトレースを取得します。さらに、テンプレートは(下記参照)、キャッシュされませんので、テンプレートへの変更は、サーバーを停止せずに有効になります。
警告
(真)のみの開発に使用されることになって、デバッグは、実稼働環境で使用すべきではありません。
さらに静かな便利な機能)は、ステートメントの実行を(変更することによって有効になっている自動リロードで、
run(reloader=True)
これは自動的にスクリプトへの変更を検出し、それが再び呼び出された後、サーバーを停止および起動することなく、新しいバージョンをリロードします。
再び、この機能は、主に開発中ではなく、生産性の高いシステムで使用されることになっています。

出力をフォーマットするボトルテンプレート

今度は、適切な形式にスクリプトの出力をキャストを見てみましょう。
実際にボトルには、文字列または関数から文字列のリストを受け取ることを想定し、ブラウザへの組み込みサーバの助けによってそれらを返します。ボトルは、文字列自体の内容については気にしないので、テキストも、HTMLマークアップを使用してフォーマットすることができます。
ボトルには、それに自身の使いやすいテンプレートエンジンをもたらします。テンプレートは、TPL拡張子を持つ別々のファイルとして保存されます。テンプレートは、関数内から次に呼び出すことができます。テンプレートは、テキストの任意の型を(ほとんどのHTMLマークアップPython文と混合される)を含めることができます。さらに、テンプレートは、例えば、引数を取ることができます結果は、テンプレート内にきれいにフォーマットされるデータベースクエリのセット。
右ここで、我々は2つ​​の列を持つ単純なテーブルに開いているのToDo項目を表示し、クエリの結果をキャストしようとしている最初の列は、番目の列のテキスト、アイテムのIDが含まれています。結果セットは、上で見たように、タプルのリストで、各タプルは、結果の1セットが含まれています。
この例ではテンプレートを含めるには、単に次の行を追加します。
from bottle import route, run, debug, template
...
result = c.fetchall()
c.close()
output = template('make_table', rows=result)
return output
...
だから我々はここで2つのことを行う: まず、我々は、テンプレートを使用できるようにするためにボトルからテンプレートをインポートします。第二に、我々は、戻された変数の出力へのmake_tableテンプレートの出力を割り当てることができます。テンプレートを呼び出すことに加えて、我々は、後にテンプレート内で使用される変数の行に、我々は、データベースクエリから受け取った結果を割り当てます。必要であれば、テンプレートに複数の変数/値を割り当てることができます。
テンプレートは常に文字列のリストを返すので、何かを変換する必要はありません。もちろん、我々は正確に上記と同じ結果が得られるリターンテンプレート( 'make_table'、行=結果)を書き込むことによって、コードの1行を保存することができます。
今ではこのようになり、対応するテンプレートを書くための時間です。
%#template to generate a HTML table from a list of tuples (or list of lists, or tuple of tuples or ...)
<p>The open items are as follows:</p>
<table border="1">
%for row in rows:
  <tr>
  %for col in row:
    <td>{{col}}</td>
  %end
  </tr>
%end
</table>
todo.pyが格納されている同じディレクトリにmake_table.tplとしてコードを保存します。
それでは、コードを見てみましょう:%で始まるすべての行は、Pythonコードとして解釈されます。もちろん、唯一の有効なPythonのステートメントが許可され、それ以外のテンプレートは他のPythonコードとして、例外が発生しますのでご注意ください。他の行はプレーンなHTMLマークアップがあります。
あなたが見ることができるように、我々は、行を通過するためには、for文を2回Pythonのを使用しています。このように、行がデータベースクエリの結果を保持する変数ですので、タプルのリストです。文の最初にリスト内のタプルは、テーブルのセルにそれぞれ配置されたタプル内の第1項目にアクセスします。 %終了したなどの文間に、それ以外の出力はあなたが期待するものではないかもしれない、場合は、あなたがすべてを閉じておくことが重要です。
テンプレート内の非Pythonのコードライン内の変数にアクセスする必要がある場合は、二重括弧に入れてする必要があります。これは、代わりに変数、右の実際の値を挿入するテンプレートを示します。
スクリプトを再度実行し、出力を見てください。それでも本当に素敵でなく、タプルのリストよりも少なくとも読みやすくなります。もちろん、あなたが上記のスパイスアップは非常に単純なHTMLマークアップは、例えば缶見栄えの良い出力を得るためにインラインスタイルを使用します。

GETとPOSTの値を使用して、

我々は適切に開いているすべての項目を確認することができますように、我々はToDoリストに新しい項目を追加して次のステップに移動します。新しいアイテムは、GETメソッドでそのデータを送信し、通常のHTMLベースのフォームから受信する必要があります。
これを行うには、まず私たちのスクリプトに新しいルートを追加し、それがGETデータを取得しなければならないルートを教えて:
from bottle import route, run, debug, template, request
...
return template('make_table', rows=result)
...

@route('/new', method='GET')
def new_item():

    new = request.GET.get('task', '').strip()

    conn = sqlite3.connect('todo.db')
    c = conn.cursor()

    c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
    new_id = c.lastrowid

    conn.commit()
    c.close()

    return '<p>The new task was inserted into the database, the ID is %s</p>' % new_id
GET(またはPOST)データにアクセスするには、我々は、ボトルからの要求をインポートする必要があります。変数に実際のデータを割り当てるには、我々は、request.GET.get('task',).strip() を使用します。タスクは、我々がアクセスするGETデータの名前であるストリップ()ステートメントを、。それがすべてです。あなたのGETデータ(複数の変数は、複数のrequest.GET.getを持っている場合)ステートメントを使用し、他の変数に割り当てることができます。
コー​​ドのこの部分の残りの部分はちょうど得られたデータの処理は次のとおりです。データベースへの書き込み、データベースから対応するIDを取得し、出力を生成します。
しかし、我々はどこからGETデータを取得するのですか?まあ、我々は、フォームを保持する静的なHTMLページを使用することができます。または、我々は今何をすべきか、root/newがGETデータなしで呼び出されると、出力されるテンプレートを使用することです。
コー​​ドでは、拡張する必要があります。
...
@route('/new', method='GET')
def new_item():

if request.GET.get('save','').strip():

    new = request.GET.get('task', '').strip()
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()

    c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
    new_id = c.lastrowid

    conn.commit()
    c.close()

    return '<p>The new task was inserted into the database, the ID is %s</p>' % new_id
else:
    return template('new_task.tpl')
new_task.tplは次のようになります。
<p>Add a new task to the ToDo list:</p>
<form action="/new" method="GET">
<input type="text" size="100" maxlength="100" name="task">
<input type="submit" name="save" value="save">
</form>
それがすべてです。あなたが見ることができるように、テンプレートはプレーン今回はHTMLです。
今、我々は行うにはリストを拡張することができます。
ところで、POSTデータを使用したい場合:これは、まったく同じように動作しますが、だけではなく、request.POST.get()を使用します。

既存のアイテムの編集

行うための最後のポイントは、既存のアイテムの編集を有効にすることです。
ルートだけを使用することによって我々はそれが可能である今のところ知っているが、かなりトリッキーかもしれません。しかし、ボトルは、このタスクは非常に簡単に "ダイナミックルート"と呼ばれる何かを知っている。
ダイナミックルートの基本的なステートメントは次のようになります。
@route('/myroute/:something')
ここでキーポイントはコロンです。これがために受け入れるようにボトルに指示します。次のスラッシュまで何か任意の文字列を。また、何かの値が、そのルートに割り当てられた関数に渡されるので、データが関数内で処理することができます。
無編集するアイテムのIDです:私たちのToDoリストについては、我々はルート@ルート(無 '/ /編集)を作成します。
コー​​ドは次のようになります。
@route('/edit/:no', method='GET')
def edit_item(no):

    if request.GET.get('save','').strip():
        edit = request.GET.get('task','').strip()
        status = request.GET.get('status','').strip()

        if status == 'open':
            status = 1
        else:
            status = 0

        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("UPDATE todo SET task = ?, status = ? WHERE id LIKE ?", (edit, status, no))
        conn.commit()

        return '<p>The item number %s was successfully updated</p>' % no
    else:
        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("SELECT task FROM todo WHERE id LIKE ?", (str(no)))
        cur_data = c.fetchone()

        return template('edit_task', old=cur_data, no=no))
いや、ここで対応する関数の番号を渡します。これはかなり基本的に我々はすでにここでの主な追加が動的経路を使用しているなどのデータをGETを使用して同じように、新しい項目を追加する際に、上記したものと同じです。あなたが見ることができるように、NOは、データベース内のデータの右側の行にアクセスする関数内で使用されていません。
関数内で呼ばれるテンプレートedit_task.tplは次のようになります。
%#template for editing a task
%#the template expects to receive a value for "no" as well a "old", the text of the selected ToDo item
<p>Edit the task with ID = {{no}}</p>
<form action="/edit/{{no}}" method="get">
<input type="text" name="task" value="{{old[0]}}" size="100" maxlength="100">
<select name="status">
<option>open</option>
<option>closed</option>
</select>
<br/>
<input type="submit" name="save" value="save">
</form>
既に上述したように再び、このテンプレートは、Pythonの文とHTMLが混在しています。
ダイナミックルートの最後の単語:後で示すようにあなたは、動的経路の正規表現を使用していてもすることができます。

ダイナミックルートの検証

ダイナミックルートを使用すると良いですが、多くのケースでそれはルートの動的な部分を検証するために理にかなっています。たとえば、我々は上記の編集のために私たちのルートの整数を期待しています。しかし、浮動小数点の場合、その文字が受信され、Pythonインタプリタは、我々が望むものではありません例外をスローします。
そのような場合には、ボトルの前に関数に渡すに "入力"を検証する@検証デコレータを提供しています。バリデータを適用するためには、次のようにコードを拡張します。
from bottle import route, run, debug, template, request, validate
...
@route('/edit/:no', method='GET')
@validate(no=int)
def edit_item(no):
...
最初に、我々は@検証 - デコレータを適用するよりも、ボトルのフレームワークから検証するインポートされます。何が整数の場合、右ここで、我々は検証しません。基本的には、検証がフロートのようなすべての種類のデータで動作し、リストなど
コー​​ドを保存し、ために "403"の値を使用して再度ページを呼び出す:いいえ、例えば、フロート。整数が期待されていたという、エラー - あなたがいない例外が、 "紫禁城403"が表示されます。
正規表現を使用した動的経路
ボトルもルートの "動的な部分が"正規表現することができますダイナミックルートを扱うことができます。
そう、ちょうど、私たちのToDoリスト内のすべての単一の項目は、例えばのような用語で、それらのプレーン番号でアクセス可能であるべきであると仮定していることを実証する"項目1"。明白な理由については、各項目のルートを作成する必要はありません。さらに、単純なダイナミックルートは、ルートの一部として、用語 "アイテム"は静的であり、いずれかの動作しません。
上記に述べたように、解決策は、正規表現です。
@route('/item:item#[1-9]+#')
def show_item(item):
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    c.execute("SELECT task FROM todo WHERE id LIKE ?", (item))
    result = c.fetchall()
    c.close()
    if not result:
        return 'This item number does not exist!'
    else:
        return 'Task: %s' %result[0]
もちろん、この例では、何らかの形で人為的に構築される - それが唯一の検証と組み合わせて単純な動的経路を使用する方が簡単でしょう。それにもかかわらず、我々は、正規表現のルートの作業方法を見たい:行@ルート(/アイテム:item_#[1-9] +#)通常のルートと同様に起動しますが、#で囲まれた部分が正規表現として解釈され、どのルートの動的な部分です。したがって、この場合には、我々は、0〜9の間の任意の数字を一致させる必要があります。次の関数 "show_item"は単に与えられた項目がデータベースかどうかに存在するかどうかを確認します。それが存在する場合には、タスクの対応するテキストが返されます。あなたが見ることができるように、ルートの唯一の正規表現の部分は前方に渡されます。さらに、それは常に、それがこのケースのように、単純な整数である場合でも、文字列として転送されます。

静的ファイルを返す

時にはそれがないPythonの関数へのルートを関連付けることが必要になるかもしれませんが、単に静的なファイルを返します。あなたは、たとえばアプリケーションのヘルプ·ページを持っているなら、あなたは普通のHTMLとしてこのページを返すようにすることができます。これは次のように動作します。
from bottle import route, run, debug, template, request, validate, static_file

@route('/help')
def help():
    return static_file('help.html', root='/path/to/file')
まず、ボトルからstatic_file関数をインポートする必要があります。あなたが見ることができるように、戻りstatic_fileステートメントは、returnステートメントを置き換えます。返されるファイルの名前とファイルへのパス:これは、少なくとも2つの引数を取ります。ファイルがアプリケーションと同じディレクトリにある場合でも、パスは記載する必要があります。しかし、この場合には、使用することができます '。'パスとして、あまりにも。ボトルを推測し、自動的にファイルのMIMEタイプが、場合には、ここでMIMEタイプ= "テキスト/html'であろうstatic_file、3番目の引数を追加し、明示的に述べたい。 static_fileは、動的なものも含めて、ルートの任意のタイプで動作します。

JSONデータを返す

あなたのアプリケーションに直接出力を生成したいのですが、データがでさらに処理されるように返されない場合、例えば、あるかもしれませんJavaScriptによる。そのような場合には、ボトルには、Webアプリケーション間でデータを交換するための標準の一種であるJSONオブジェクトを返すように可能性を提供しています。さらに、JSONはPythonを含め、多くのプログラミング言語で処理することができ
だから、Let 'sは、我々はJSONオブジェクトとして正規表現の経路の例で生成されたデータを返すようにしたいと仮定します。コー​​ドは次のようになります。
@route('/json:json#[1-9]+#')
def show_json(json):
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    c.execute("SELECT task FROM todo WHERE id LIKE ?", (json))
    result = c.fetchall()
    c.close()

    if not result:
        return {'task':'This item number does not exist!'}
    else:
        return {'Task': result[0]}
することができますように、その非常に簡単です:単に通常のPython辞書とボトルを返すと、送信する前にJSONオブジェクトに自動的に変換されます。ですから、例えばもし"http://localhost/json1"ボトルと呼ぶこの場合にはJSONオブジェクトを返す必要があります{"タスク":["Pythonに優れた入門書を取得するために、バイトの-pythonを読む"]}。

エラーのキャッチ

次のステップは、アプリケーションのユーザーからのエラーメッセージのいずれかのタイプを遠ざけるために、ボトル自体にエラーをキャッチすることであるかもしれません。これを行うには、ボトルは、HTMLエラーに割り当てることができます "というエラー·ルート"を持っています。
私たちのケースでは、403エラーをキャッチしたいと思います。次のようにコードは次のとおりです。
from bottle import error

@error(403)
def mistake(code):
    return 'The parameter you passed has the wrong format!'
だから、最初に我々は、ボトルからエラーをインポートし、すべての "403 Forbidden"エラーをキャッチし、エラー(403)によって経路を定義する必要があります。関数は "間違い"がそれに割り当てられています。あなたがそれを必要としない場合でも、 - エラー()は常に関数にエラーコードを渡すことに注意してください。したがって、関数は常に一つの引数を受け取る必要があり、それ以外の場合は動作しません。
再び、関数に複数のエラーのルートを割り当てる、または1つの機能それぞれにさまざまなエラーをキャッチすることができます。このコードのように:
@error(404)
@error(403)
def mistake(code):
    return 'There is something wrong!'
次の1つは同様に、正常に動作します。
@error(403)
def mistake403(code):
    return 'The parameter you passed has the wrong format!'

@error(404)
def mistake404(code):
    return 'Sorry, this page does not exist!'

要約

上記のすべてのセクションを通過した後は、ボトルWSGIフレームワークがどのように動作する簡単な理解しておく必要があります。さらに、あなたのアプリケーションのためにボトルを使用するために必要なすべての知識を持っています。
次の章では、大規模なプロジェクトのためにボトルに適応する方法を簡単に紹介を提供します。さらに、我々はこれまでに使用されるものよりも高い負荷/より多くのWebトラフィックのパフォーマンスが向上し、Webサーバーとボトルを操作する方法を示します。

サーバーのセットアップ

これまでのところ、我々は、Pythonに付属のWSGIリファレンスサーバーであるボトルで使用される標準的なサーバを使用していました。このサーバは、開発目的のために完璧に適していますが、それは大規模なアプリケーションのために本当に適していません。我々は選択肢を見ている前に、のは、まず標準的なサーバーの設定を微調整する方法を見てみましょう。

別のポートとIPアドレスにボトルを実行する

標準として、ボトルもlocalhostとして知られているIPアドレス127.0.0.1上、ポート8080でページを提供します。追加のパラメータは、ポートとアドレスを変更するには、ボトルのrun()関数に渡すことができるように設定を変更するには、非常に単純です。
ポートを変更するには、runコマンドにポート=ポート番号を追加します。したがって、たとえば:
run(port=80)
ボトルは、ポート80をリッスンするでしょう。
:ボトルがリッスンしているIPアドレスを変更するには
run(host='123.45.67.89')
もちろん、両方のパラメータが同じように、組み合わせることができます。
run(port=80, host='123.45.67.89')
ボトルは別のサーバーで実行されているときに、ポートおよびホストパラメータは、次のセクションに示すように、適用することができます。

別のサーバーにボトルを実行する

上記に述べたように、標準のサーバ、開発、個人的な使用のみボトルに基づいてアプリケーションを使用している人々の小さなグループのために完璧に適しています。それはシングルスレッドであるとして大規模なタスクのために、標準のサーバーは、ボトルネックになる可能性があり、したがって、それだけで一度に1つの要求を提供することができます。
しかし、ボトルは、すでに高い負荷でパフォーマンスが向上し、ボード上のマルチスレッド·サーバーへの各種アダプタを持っています。ボトルは、CherryPyをFapws3、flupのと貼り付けをサポートしています。
[貼り付け]サーバとの例では、ボトルのために実行する場合は、次のコードを使用します。
from bottle import PasteServer
...
run(server=PasteServer)
これはFlupServer、CherryPyServerとFapwsServerとまったく同じように動作します。

mod_wsgiのApacheとでボトルを実行する

多分あなたは既にApacheがありますか、ボトルベースの​​アプリケーションを大規模に実行したい - それはmod_wsgiでApacheを考える時間です。
私達はあなたのApacheサーバーが稼働中で、mod_wsgiをも同様に正常に動作していることを前提としています。 Linuxディストリビューションの多くに、mod_wsgiのが容易に使用されているどのようなパッケージ管理システムを介してインストールすることができます。
ボトルはそれとmod_wsgiのためのアダプタをもたらすので、あなたのアプリケーションを提供するのは簡単な作業です。
次の例では、我々は、あなたのアプリケーションが "ToDoリスト"を作成することを前提としていhttp://www.mypage.com/todo、コード、テンプレート、SQLiteデータベースを介してアクセスがパスに格納されているの/ var / www / TODO 。
あなたがmod_wsgiを介してアプリケーションを実行すると、それはrun()あなたのコードからステートメントを削除することが不可欠です、それ以外の場合は、ここでは動作しません。
その後、次の内容のadapter.wsgiというファイルを作成します。
import sys, os, bottle

sys.path = ['/var/www/todo/'] + sys.path
os.chdir(os.path.dirname(__file__))

import todo # This loads your application

application = bottle.default_app()
との/ var / www / TODO、同じパスに保存してください。実際にファイルの名前は、長い拡張子があるので、何もすることができます。WSGI。名前は、仮想ホストからファイルを参照するために使用されています。
最後に、我々は次のようになります。Apacheの設定に仮想ホストを追加する必要があります。
<VirtualHost *>
    ServerName mypage.com

    WSGIDaemonProcess todo user=www-data group=www-data processes=1 threads=5
    WSGIScriptAlias / /var/www/todo/adapter.wsgi

    <Directory /var/www/todo>
        WSGIProcessGroup todo
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>
サーバを再起動した後、あなたのToDoリストには、http://www.mypage.com/todoでアクセス可能でなければなりません

最後の言葉

今、私たちはボトルには、この導入とチュートリアルの最後にあります。我々は、ボトルの基本的な概念について学んだとボトルのフレームワークを使用した最初のアプリケーションを作成しました。それに加えて、我々は、大規模なタスクのためのボトルを適応し、mod_wsgiのでApacheウェブサーバを介してボトルを提供する方法を説明しました。
導入で述べたように、このチュートリアルでは、ボトルのすべての色合いと可能性を示していません。私たちはここではスキップすること例えばですファイルオブジェクトとストリームを受信する方法と、認証データを処理する。さらに、テンプレートを別のテンプレート内から呼び出すことができますどのように表示されませんでした。これらの点への導入については、フルボトルのマニュアルを参照してください。 完全な例リスト
ToDoリストの例は、ピース単位で開発されたとして、ここでは、完全なリストは、次のとおりです。
アプリケーションtodo.pyのメインのコード:
import sqlite3
from bottle import route, run, debug, template, request, validate, static_file, error

# only needed when you run Bottle on mod_wsgi
from bottle import default_app

@route('/todo')
def todo_list():

    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    c.execute("SELECT id, task FROM todo WHERE status LIKE '1';")
    result = c.fetchall()
    c.close()

    output = template('make_table', rows=result)
    return output

@route('/new', method='GET')
def new_item():

    if request.GET.get('save','').strip():

        new = request.GET.get('task', '').strip()
        conn = sqlite3.connect('todo.db')
        c = conn.cursor()

        c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
        new_id = c.lastrowid

        conn.commit()
        c.close()

        return '<p>The new task was inserted into the database, the ID is %s</p>' % new_id

    else:
        return template('new_task.tpl')

@route('/edit/:no', method='GET')
@validate(no=int)
def edit_item(no):

    if request.GET.get('save','').strip():
        edit = request.GET.get('task','').strip()
        status = request.GET.get('status','').strip()

        if status == 'open':
            status = 1
        else:
            status = 0

        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("UPDATE todo SET task = ?, status = ? WHERE id LIKE ?", (edit,status,no))
        conn.commit()

        return '<p>The item number %s was successfully updated</p>' %no

    else:
        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("SELECT task FROM todo WHERE id LIKE ?", (str(no)))
        cur_data = c.fetchone()

        return template('edit_task', old = cur_data, no = no)

@route('/item:item#[1-9]+#')
def show_item(item):

        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("SELECT task FROM todo WHERE id LIKE ?", (item))
        result = c.fetchall()
        c.close()

        if not result:
            return 'This item number does not exist!'
        else:
            return 'Task: %s' %result[0]

@route('/help')
def help():

    static_file('help.html', root='.')

@route('/json:json#[1-9]+#')
def show_json(json):

    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    c.execute("SELECT task FROM todo WHERE id LIKE ?", (json))
    result = c.fetchall()
    c.close()

    if not result:
        return {'task':'This item number does not exist!'}
    else:
        return {'Task': result[0]}


@error(403)
def mistake403(code):
    return 'There is a mistake in your url!'

@error(404)
def mistake404(code):
    return 'Sorry, this page does not exist!'


debug(True)
run(reloader=True)
#remember to remove reloader=True and debug(True) when you move your application from development to a productive environment
テンプレートmake_table.tpl:
%#template to generate a HTML table from a list of tuples (or list of lists, or tuple of tuples or ...)
<p>The open items are as follows:</p>
<table border="1">
%for row in rows:
  <tr>
  %for col in row:
    <td>{{col}}</td>
  %end
  </tr>
%end
</table>
テンプレートedit_task.tpl:
%#template for editing a task
%#the template expects to receive a value for "no" as well a "old", the text of the selected ToDo item
<p>Edit the task with ID = {{no}}</p>
<form action="/edit/{{no}}" method="get">
<input type="text" name="task" value="{{old[0]}}" size="100" maxlength="100">
<select name="status">
<option>open</option>
<option>closed</option>
</select>
<br/>
<input type="submit" name="save" value="save">
</form>
Template new_task.tpl:
%#template for the form for a new task
<p>Add a new task to the ToDo list:</p>
<form action="/new" method="GET">
<input type="text" size="100" maxlength="100" name="task">
<input type="submit" name="save" value="save">
</form>

2013年2月3日日曜日

CentOSでCUIのメール環境を構築する


CentOSでCUIのメール環境を構築する

ここでは、下記にミドルウエアの環境構築を行います。
1. Heirloom mailx
2. postfix

Heirloom mailx

1. 概要

Heirloom mailxとは、
/bin/mailの拡張版ともいえる、「Heirloom mailx」をインストールします。 「Heirloom mailx」は、IMAP、POP3、APOP、SSL/TLS、S/MIMEに対応したLinux版のCUIメーラです。

2. インストール

以下のコマンドでインストールを行います
$ cd /usr/local/src
$ wget http://sourceforge.net/projects/heirloom/files/latest/download
$ tar -jxf mailx-12.4.tar.bz2
$ cd mailx-12.4
# make
# make install UCBINSTALL=/usr/bin/install

3. 環境設定

利用するユーザ単位で、.mailrcを作成します ここでは、Gmailのメールサーバを利用することにします
$ vim ~/.mailrc
# .mailrc Gmail config
account gmail {
   set imap-cache=~/MailDir
   set imap-use-starttls
   set folder=imaps://Gmailのユーザ名@gmail.com@imap.gmail.com
   set password-Gmailのユーザ名@gmail.com@imap.gmail.com=Gmailのパスワード 
   set from=”お名前 <Gmailのユーザ名@gmail.com>”
   set record=+Sent
   set smtp-use-starttls
   set smtp=smtp://smtp.gmail.com:587
   set smtp-auth=login
   set smtp-auth-user=Gmailのユーザ名@gmail.com
   set smtp-auth-password=Gmailのパスワード
   set nss-config-dir=~/.mozilla/firefox/xxxxxxx.xxxx プロファイル情報
   shortcut allmail +[Gmail]/All\ Mail
   shortcut spam +[Gmail]/Spam
   shortcut trash +[Gmail]/Trash
}
標準では無いmailxを起動するように.bashrcの最終行に定義の追加 念のために、PAGERの定義も追加する。
# vi .bashrc

alias mailx=/usr/local/bin/mailx
export PAGER=/usr/bin/less

4. Gmailの参照

下記のコマンドでGmailを読みます。
# mailx -A gmail <---- gmailは、.mailrc で定義したアカウント
正しく設定されていれば、メールの一覧が表示されます。
mailxコマンドのオプション詳細

postfixの設定

1. Gmailに接続するには、認証用のモジュールをインストールする。

下記をインストール
# yum install cyrus-sasl
# yum install /usr/bin/c_rehash

2. Gmailの証明書を取得

# openssl s_client -connect smtp.gmail.com:465 -showcerts
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
i:/C=US/O=Google Inc/CN=Google Internet Authority
ここから
-----BEGIN CERTIFICATE-----

-----END CERTIFICATE-----
ここまでを/etc/pki/tls/certs/google.pem として保存
1 s:/C=US/O=Google Inc/CN=Google Internet Authority
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
ここから
-----BEGIN CERTIFICATE-----

-----END CERTIFICATE-----
ここまでを/etc/pki/tls/certs/euqifax.pem として保存

3. postfixの認証データを作成

証明書をハッシュ化
# c_rehash /etc/pki/tls/certs
Doing /etc/pki/tls/certs
google.pem => xxxxxxxx.0
euqifax.pem => xxxxxxxx.0

4. gmailのパスワードファイル作成

# vi /etc/postfix/auth_passwd
[smtp.gmail.com]:587 xxxxx@gmail.com:password
# chown root. /etc/postfix/auth_passwd
# chown 600 /etc/postfix/auth_passwd
ファイルを更新したらpostmapを必ず実行
# postmap /etc/postfix/auth_passwd

5. Postfixの設定

# vi /etc/postfix/main.cf
relayhost = [smtp.gmail.com]:587
smtp_use_tls = yes

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/auth_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain

smtp_tls_CApath = /etc/pki/tls/certs
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
Postfixを再起動
# /etc/init.d/postfix restart これで設定は終了です。

6. メール送信の確認

# mailx -s "TEST"  XXXXX@gmail.com
テストメールを送ってみます。
.
EOF

エラーがないか/var/log/maillogを確認ください。
# tail -1000 /var/log/maillog

参考URL