2013年2月4日月曜日

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>

0 件のコメント:

コメントを投稿