Hatena::ブログ(Diary)

nagaetty.py

2012-09-24 Bottleチュートリアル(日本語訳)

Bottle Tutorial(日本語訳)は、下記のURLの情報を訳したものです。

http://bottlepy.org/docs/dev/tutorial.html

チュートリアル

このチュートリアルでは、ボトルのWebフレームワークの概念と機能を紹介し、同様に基本的かつ高度なトピックをカバーしています。あなたが最初から最後までそれを読んで、またはそれ以降のrefecenceとして使用することができます。自動的に生成されたAPIリファレンスにも、あなたにとっては興味深いかも知れません。それ以上の詳細について説明しますが、このチュートリアル未満を説明しています。最も一般的な質問のためのソリューションは、当社のレシピ集やFAQページに記載されています。何か助けが必要な場合は、私たちのメーリングリストに参加したり、私たちのIRCチャン​​ネルで私たちをご覧ください。

インストール

ボトルは、任意の外部ライブラリに依存しません。あなたは自分のプロジェクトディレクトリにbottle.pyダウンロードしてコーディングを開始することができます。

$ wget http://bottlepy.org/bottle.py

これは、すべての新機能が含まれています最新の開発スナップショットを取得します。あなたがより安定した環境を好む場合には、安定版リリースに固執する必要があります。これらはPyPi上で利用可能であり、PIP(推奨)、easy_installや、パッケージマネージャを介してインストールすることができます。

$ sudo pip install bottle # recommended

$ sudo easy_install bottle # alternative without pip

$ sudo apt-get install python-bottle # works for debian, ubuntu, ...

いずれかの方法では、ボトルのアプリケーションを実行するためにはPython 2.5以降を(3.xを含む)が必要です。 :あなたは、システム全体、あるいは単に、最初virtualenvを作成したくないパッケージをインストールする権限を持っていない場合

$ virtualenv develop # Create virtual environment

$ source develop/bin/activate # Change default python to virtual one

(develop)$ pip install -U bottle # Install bottle to virtual environment

または、virtualenvのは、お使いのシステムにインストールされていない場合:

$ wget https://raw.github.com/pypa/virtualenv/master/virtualenv.py

$ python virtualenv.py develop # Create virtual environment

$ source develop/bin/activate # Change default python to virtual one

(develop)$ pip install -U bottle # Install bottle to virtual environment

クイックスタート: "Hello World"

このチュートリアルでは、どちらかのボトルをインストールしたり、プロジェクトディレクトリにコピーしたと仮定しています。非常に基本的な "Hello World"の例から始めましょう:

from bottle import route, run

@route('/hello')

def hello():

return "Hello World!"

run(host='localhost', port=8080, debug=True)

これがそれです。このスクリプトを実行​http://localhost:8080/helloを訪問し、あなたのブラウザに "Hello World!"を表示されます。ここにそれがいかにが働くかある:

route() デコレータは、URLパスのコードの一部をバインドします。このケースでは、hello()関数に/こんにちはURLをリンクします。これは、ルート(したがって、デコレータ名)と呼ばれ、この枠組みの中で最も重要な概念です。必要な数だけルートとして定義することができます。ブラウザURLを要求するたびに、関連付けられた関数が呼び出され、戻り値ブラウザに送り返されます。そのように、そのような単純な。

最後の行にあるrun()は、組み込みの開発サーバーを起動します。これは、localhostのポート8080上で実行され、Control-cを押すまで、リクエストを提供しています。後でサーバーのバックエンドを切り替えることができますが、ここで開発用サーバは、我々が必要とするすべてである。それは全く設定を必要とせず、あなたのアプリケーションを取得し、ローカルテストのために実行するには、信じられないほど痛みのない方法です。

デバッグ·モードでは、初期の開発時に非常に便利ですが、公開されたアプリケーションのためにオフにする必要があります。このことを念頭に置いて保管してください。

もちろん、これは非常に単純な例ですが、それはアプリケーションがボトルで構築されている方法の基本的な考え方を示しています。読み続け、あなたは可能性があり、他に何がわかります。

デフォルトアプリケーション

簡潔さのために、このチュートリアルでは、ほとんどの例では、ルートを定義するデコレータモジュールレベルのroute()を使用します。これはグローバルな "デフォルトアプリケーション"、自動的にroute()を呼び出して初めて作成されたボトルのインスタンスへのルートを追加します。他のいくつかのモジュールレベルのデコレータ関数は、このデフォルトアプリケーションに関連していますが、より多くのオブジェクト指向のアプローチを好むと余分なタイピングを気にしない場合は、別のアプリケーションオブジェクトを作成し、グローバルなものの代わりにそのを使用することができます。

from bottle import Bottle, run

app = Bottle()

@app.route('/hello')

def hello():

return "Hello World!"

run(app, host='localhost', port=8080)

オブジェクト指向のアプローチは、さらにデフォルトアプリケーションのセクションで説明されています。ちょうどあなたが選択を持っていることを心に留めておいてください。

ルーティング要求

最後の章では、単一のルートで非常に単純なWebアプリケーションを構築しました。ここで再び "Hello World"の例のルーティング部分は、次のとおりです。

@route('/hello')

def hello():

return "Hello World!"

ルート()デコレータは、コールバック関数へのURLパスをつなぐと、デフォルトアプリケーションへの新しいルートを追加します。一つの経路を持つアプリケーションは、しかし、ボーリングのようなものです。さらにいくつか追加してみましょう。

@route('/')

@route('/hello/<name>')

def greet(name='Stranger'):

return 'Hello %s, how are you?' % name

この例では、2つのことを示しています:あなたは、単一のコールに複数のルートにバインドすることができ、URLワイルドカードを追加し、キーワード引数を介してアクセスすることができます。

ダイナミックルート

ワイルドカードを含むルートがダイナミックルートと呼ばれる(静的ルートとは対照的に)と、同時に複数のURLと一致しています。単純なワイルドカードは、角括弧で囲まれた名前(例えば<NAME>)から成り、次のスラッシュ(/)に1つまたは複数の文字を受け入れます。たとえば、ルート/こんにちは/ <name>は/こんにちは/ボブとしてではなく、/ HELLO、HELLO / /または/こんにちは/ MR / smithの同様に/こんにちは/ aliceの要求を受け入れます。

ワイルドカードはリクエストのコールバックへのキーワード引数としてURLの覆われた部分を渡します。あなたはすぐにそれらを使用すると簡単にRESTfulな、見栄えの良い、有意義URLを実装することができます。ここで、それらが一致するだろうのURLと一緒にいくつかの他の例は、次のとおりです。

@route('/wiki/<pagename>') # matches /wiki/Learning_Python

def show_wiki_page(pagename):

...

@route('/<action>/<user>') # matches /follow/defnull

def user_api(action, user):

...

バージョン0.10の新機能。

フィルタは、それがコールバックに渡される前にURLの覆われた部分をより具体的なワイルドカードを定義する、および/または変換するために使用されています。フィルタワイルドカード<name:filter>または<name:filter:config>として宣言されています。オプションの設定部分の構文は、使用されているフィルタに依存しています。

次のフィルタデフォルトで実装され、より多くの追加されることがあります。

●:int型のみの一致(符号付き)の数字と値を整数に変換します。

●:float型が小数のために:に似て浮かんでいる。

●:pathは、非欲張りのようにスラッシュ文字を含むすべての文字と一致し、複数のパスセグメントを一致させるために使用することができます。

●:reは、configフィールドにカスタムの正規表現を指定することができます。一致した値は変更されません。

それでは、いくつかの実用的な例を見てみましょう:

@route('/object/<id:int>')

def callback(id):

assert isinstance(id, int)

@route('/show/<name:re:[a-z]+>')

def callback(name):

assert name.isalpha()

@route('/static/<path:path>')

def callback(path):

return static_file(path, ...)

あなたにも独自のフィルタを追加することができます。詳細についてはルーティングを参照してください。

バージョン0.10で変更されました。

新しいルールの構文は、いくつかの一般的なユースケースを簡素化するためボトル0.10で導入されましたが、古い構文はまだ動作し、あなたがまだそれを使用するコード例をたくさん見つけることができました。違いは、最高の例で説明されています。

Old Syntax New Syntax

:name <name>

:name#regexp# <name:re:regexp>

:#regexp# <:re:regexp>

:##       <:re>

可能であれば、将来のプロジェクトで、古い構文を避けるようにしてください。それは現在廃止されていませんが、最終的になります。

HTTPリクエストメソッド

HTTPプロトコルは、さまざまなタスクのいくつかのリクエストのメソッドを(時には "動詞"と呼ばれる)を定義します。指定されていない他のメソッドを持つすべてのルートのデフォルトはgetになります。これらのルートは、GET要求にマッチします。 POSTなど他のメソッドを処理するには、PUTやDELETEは、route()デコレータメソッドキーワード引数を追加したり、4つの代替デコレータのいずれかを使用します。)(GET、POST()()(プット)または削除します。

POSTメソッドは、一般的にHTMLフォームの送信に使用されます。この例では、POSTを使用してログインフォームを処理する方法を示しています。

from bottle import get, post, request

@get('/login') # or @route('/login')

def login_form():

return '''

'''

@post('/login') # or @route('/login', method='POST')

def login_submit():

name = request.forms.get('name')

password = request.forms.get('password')

if check_login(name, password):

return "

Your login was correct

"

else:

return "

Login failed

"

この例では、/ログインURLは、二つの異なるコールバック、GET要求およびPOST要求のために別のものにリンクされています。一つ目は、ユーザーにHTMLフォームが表示されます。番目のコールバックは、フォームのサブミット時に呼び出され、ユーザーがフォームに入力されたログイン資格情報がチェックされます。 Request.formsの使用はさらに要求データのセクションに記載されています。

特殊なメソッド:HEADとANY

HEADメソッドは、GET要求に相当するものと同一の応答を求めるために使用されますが、レスポンス·ボディなしでされています。これは、文書全体をダウンロードせずに、リソースに関するメタ情報を取得するのに便利です。存在する場合、ボトルは、対応するgetルートにフォールバックし、要求の本体を切断することによって、自動的にこれらの要求を処理します。任意のHEADルートを自分で指定する必要はありません。

さらに、非標準のメソッドはすべて低い優先度のフォールバックとして動作します:ANYに耳を傾けるのルートに関係なく、HTTPメソッドの要求と一致しますが、他のより具体的なルートが定義されていない場合のみです。これは、サブアプリケーションより具体的に要求をリダイレクトするプロキシのルートのために有用です。

それを要約すると:HEADリクエストは、経路をGETにフォールバックし、すべての要求は、任意のルートにフォールバックしますが、元のリクエストメソッドに対して一致するルートが存在しない場合のみです。それはそれと同じくらい簡単です。

静的ファイルのルーティング

このような画像やCSSファイルなどの静的ファイルは自動的に提供されません。あなたは、ルートと提供されるファイルとそれらを見つけるために場所を制御するコールバックを追加する必要があります。

from bottle import static_file

@route('/static/<filename>')

def server_static(filename):

return static_file(filename, root='/path/to/your/static/files')

static_file()関数は、(静的ファイルを参照してください)​​安全かつ便利な方法でファイルを提供するためのヘルパーです。 <filename>のワイルドカードがそれにスラッシュでパスと一致しませんので、この例では、/path/to/your/static/filesに制限されています。サブディレクトリ内のファイルを提供するには、パス·フィルタを使用するためにワイルドカードを変更します。

@route('/static/<filepath:path>')

def server_static(filepath):

return static_file(filepath, root='/path/to/your/static/files')

rootなどの相対的なルートパス= './static/files'を指定するときは注意してください。作業ディレクトリ(./)とプロジェクトディレクトリは、常に同じではありません。

エラーページ

何かがうまくいかない場合、ボトルは有益でもかなり単純なエラーページが表示されます。あなたは、エラー()デコレータを持つ特定のHTTPステータスコードデフォルトを上書きすることができます。

from bottle import error

@error(404)

def error404(error):

return 'Nothing here, sorry'

今から、404ファイルが見つかりませんエラーがユーザーにカスタムエラーページが表示されます。エラー·ハンドラに渡される唯一のパラメータはHTTPErrorのインスタンスです。それとは別に、エラーハンドラは、通常のリクエストのコールバックと非常によく似ています。あなたは、リクエストから読み取られた応答への書き込みとHTTPErrorインスタンスを除くすべてのサポートされているデータ型を返すことができます。

アプリケーションが返すかHTTPError例外発生した場合、エラーハンドラにのみ使用されます(中止すること()だけのことありません)。 Request.statusを変更したり、HttpResponseを返すことはエラーハンドラをトリガしません。

コンテンツを生成する

純粋なWSGIでは、アプリケーションから返されることがありますタイプの範囲は非常に限られている。アプリケーションがiterableの降伏バイト文字列を返す必要があります。あなたは、文字列を返すことがあります(文字列がiterableであるため)が、この原因は、ほとんどのサーバーでは、charchar型コンテンツを送信する。 Unicode文字列は全く許可されていません。これは非常に実用的ではありません。

ボトルは、はるかに柔軟であり、幅広い種類のをサポートしています。それが可能な場合でも、Content-Lengthヘッダを追加し、自動的にUnicodeエンコードされますので、あなたがする必要はありません。あなたは、アプリケーションのコールバックと、これらはフレームワークによって処理される方法の簡単な説明からの復帰可能性のあるデータ型のリストはどのような次のとおりです。

辞書

前述したように、Pythonの辞書は(またはそのサブクラス)は、自動的にJSON文字列に変換され、application /jsonに設定するには、Content-Typeヘッダでブラウザに返されます。これは、JSONベースのAPIの実装を容易にします。 JSON以外のデータ形式があまりにもサポートされています。多くを学ぶためのチュートリアル - 出力フィルタを参照してください。

空の文字列は、False、Noneまたは他の非真の値:

これらは0に設定し、Content-Lengthヘッダを持つ空の出力を生成します。

Unicode文字列

Unicode文字列(またはUnicode文字列を得イテラブル)が自動的にContent-Typeヘッダ(デフォルトでUTF8)で指定されたコーデックエンコードされたとします(下記参照)、通常のバイト文字列として扱われます。

バイト文字列

ボトルは、全体として文字列を返します(代わりに各char型を反復処理)、文字列の長さに基づいて、Content-

Lengthヘッダを追加します。バイト文字列のリストが最初に結合されます。彼らはメモリに収まるように大きすぎて成長する可能性があるため、バイト文字列が得られる他のイテラブルは結合されません。 Content-Lengthヘッダは、このケースでは設定されていません。

HTTPErrorまたはHttpResponseのインスタンス

これらを返すことは例外として、それらを発生させる場合と同じ効果があります。 HTTPErrorの場合には、エラーハンドラが適用されます。詳細については、エラー·ページを参照してください。

ファイルオブジェクト

。read()メソッドを持っている物は全て、ファイルまたはファイルのようなオブジェクトとして扱われ、WSGIサーバフレームワークによって定義された呼び出し可能なwsgi.file_wrapperに渡されます。いくつかのWSGIサーバ実装はより効率的にファイルを送信するために最適化されたシステムコールの使用(sendfileを)作ることができます。他のケースで、これは単にメモリに収まるチャンクを反復します。このようにContent-LengthやContent-Typeなどのオプションのヘッダーは自動的に設定されていません。可能であれば、send_file()を使用します。詳細については、静的なファイルを参照してください。

イテラブルとジェネレータ

あなたは、あなたのコールバック内で収量を使用するか、または反復可能な、iterableの利回りバイト文字列に限り、Unicode文字列、またはHTTPErrorのHttpResponseインスタンスを返すことが許可されています。入れ子になったイテラブルは申し訳ありませんが、サポートされていません。 HTTPステータスコードとヘッダが、すぐにiterableの利回りとしての最初の非空の値をブラウザに送信されることに注意してください。これらを変更すると、後で効果がありません。

このリストの順序は重要である。次の例のようにread()メソッドでstrのサブクラスを返すことがあります。文字列が最初に処理されるため、それはまだ、代わりにファイルの文字列として扱われます。

デフォルトエンコーディングを変更する

ボトルは、Unicode文字列エンコードする方法を決定するためにContent-Typeヘッダのcharsetパラメータを使用しています。 text / htmlに、このヘッダーのデフォルト値は、直接Response.Charsetを属性を設定することのcharset = UTF8とResponse.content_type属性を使用するか、または変更することができます。 (Responseオブジェクトは、セクションレスポンスオブジェクトに記述されています。)

ボトルのインポート応答から

from bottle import response

@route('/iso')

def get_iso():

response.charset = 'ISO-8859-15'

return u'This will be sent with ISO-8859-15 encoding.'

@route('/latin9')

def get_latin():

response.content_type = 'text/html; charset=latin9'

return u'ISO-8859-15 is also known as latin9.'

まれに、Pythonエンコーディング名は、HTTP仕様でサポートされている名前とは異なります。次に、両方を行う必要があります:最初のResponse.content_typeヘッダを(変更せずにクライアントに送られます)を設定してから、(Unicodeエンコードするために使用されている)Response.Charsetを属性を設定します。

静的ファイル

直接ファイルオブジェクトを返すことができますが、static_file()は静的ファイルを提供するための推奨方法です。自動的に推測するのmime-typeは、Last-Modifiedヘッダを追加し、セキュリティ上の理由から、ルートディレクトリへのパスを制限し、適切なエラー応答(許可エラーの401、行方不明のファイルの404)を生成します。それも、If-Modified-Sinceヘッダーをサポートしており、最終的に304 Not Modifiedを応答を生成します。あなたは、推測を無効にするには、カスタムのMIMEタイプを渡すことができます。

from bottle import response

@route('/iso')

def get_iso():

response.charset = 'ISO-8859-15'

return u'This will be sent with ISO-8859-15 encoding.'

@route('/latin9')

def get_latin():

response.content_type = 'text/html; charset=latin9'

return u'ISO-8859-15 is also known as latin9.'

あなたが本当にする必要があれば、例外としてstatic_file()の戻り値を上げることができます。

強制ダウンロード

ほとんどのブラウザMIMEタイプが知られているアプリケーション(例えばPDFファイル)に割り当てられている場合、ダウンロードしたファイルを開こうとします。これはあなたが望むものでない場合は、ダウンロードダイアログを強制的にでもユーザーにはファイル名を示唆することができます。

@route('/download/<filename:path>')

def download(filename):

return static_file(filename, root='/path/to/static/files', download=filename)

ダウンロードパラメータが単にTrueの場合、元のファイル名が使用されます。

HTTPエラーとリダイレクト

abort()関数は、HTTPエラーページを生成するためのショートカットです。

from bottle import route, abort

@route('/restricted')

def restricted():

abort(401, "Sorry, access denied.")

別のURLクライアントリダイレクトするには、新しいURLに設定するLocationヘッダを持つ他の応答を参照してください303を送信することができます。あなたのためにそれをしない)(リダイレクトします。

from bottle import redirect

@route('/wrong/url')

def wrong():

redirect("/right/url")

あなたは番目のパラメータとして別のHTTPステータスコードを提供することがあります。

注意

どちらの関数もHTTPError例外を発生させることによって、コールバックコードが中断されます。

その他の例外

HTTPResponseはまたはHTTPError以外のすべての例外は、500内部サーバーエラー応答になりますので、彼らはあなたのWSGIサーバがクラッシュすることはありません。あなたがbottle.app().catchallにFalseを設定することで、ミドルウェアで例外を処理するために、この動作をオフにすることができます。

レスポンスオブジェクト

そのようなHTTPステータスコード、レスポンスヘッダおよびクッキーのような応答メタデータは、それがブラウザに送信される点に対応し、最大と呼ばれるオブジェクトに格納されています。直接これらのメタデータを操作したり、これを行うには事前に定義されたヘルパー·メソッドを使用することができます。完全なAPIと機能のリストは、APIセクション(応答を参照)で説明されていますが、最も一般的なユースケースと機能はあまりにも、ここでカバーされています。

状態コード

HTTPステータスコードが200 OK、ブラウザデフォルトの動作を制御します。ほとんどのシナリオでは、手動でのResponse.Status属性を設定する必要がありますが、中止()ヘルパーを使用するか、または適切なステータスコードを使用してHTTPResponseインスタンスを返しません。任意の整数は許可されているが、HTTP仕様で定義されている以外のコードは、ブラウザのみ、ブレーク基準を混乱させます。

レスポンスヘッダ

Cache-Controlや場所などのレスポンスヘッダがResponse.set_header()を介して定義されています。このメソッドは二つのパラメータ、ヘッダ名と値をとります。名前の部分は大文字小文字を区別しません:

@route('/wiki/<page>')

def wiki(page):

response.set_header('Content-Language', 'en')

...

ほとんどのヘッダには、名前ごとに1つのヘッダがクライアントに送信であることを意味し、ユニークです。いくつかの特別なヘッダは、しかし、応答で複数回表示されるように許可されています。追加のヘッダーを追加するには、代わりにResponse.set_header()のResponse.add_header()を使用します。

response.set_header('Set-Cookie', 'name=value')

response.add_header('Set-Cookie', 'name2=value2')

これは単なる例であることに注意してください。あなたはクッキーを操作する場合は、このまま読み進めてください。

クッキー

クッキーは、ユーザーのブラウザプロファイルに格納されているテキストの名前部分です。あなたがRequest.get_cookie()を介して以前に定義されたクッキーにアクセスし、Response.set_cookie()で新しいクッ​​キーを設定することができます。

@route('/hello')

def hello_again():

if request.get_cookie("visited"):

return "Welcome back! Nice to see you again"

else:

response.set_cookie("visited", "yes")

return "Hello there! Nice to meet you"

Response.set_cookie()メソッドは、クッキーの寿命と動作を制御する追加のキーワード引数の数を受け入れます。最も一般的な設定のいくつかはここで説明されています。

max_age:最大年の秒数表記。 (デフォルト:なし)

expires: datetimeオブジェクトまたはUNIXタイムスタンプ。 (デフォルト:なし)

domain:クッキーの読み取りを許可されているドメイン。 (デフォルト:現在のドメイン

path:指定されたパスにCookieを制限する(デフォルト:/)

secure: (デフォルト:オフ)HTTPS接続にクッキーを制限します。

httponly:このCookieは読むために、クライアント側のJavaScriptを防止する(デフォルト:オフとは、Python2.6またはそれ以降が必要です)。

どちらもも保つように設定されている有効期限が切れた場合、クッキーは、ブラウザセッションの終了時または、すぐにブラウザのウィンドウが閉じられるように有効期限が切れます。クッキーを使用する際に考慮すべきいくつかの他の落とし穴があります。

クッキーはほとんどのブラウザ内のテキストの4キロバイトに制限されています。 一部のユーザーがすべてではクッキーを受け入れないようにブラウザを設定します。ほとんどの検索エンジンにもクッキーを無視します。アプリケーションはまだクッキーなしで動作することを確認します。 クッキーは、クライアント側で保存され、どのような方法で暗号化されていません。クッキーに保存何であれ、ユーザがそれを読むことができます。それよりもさらに悪いことに、攻撃者があなたの側にXSS脆弱性を介してユーザーのcookieを盗むことができるかもしれません。一部のウイルスはあまりにも、ブラウザCookieを読み取ることが知られています。したがって、クッキーに機密情報を格納することはありません。 クッキーは簡単に悪意のあるクライアントによって偽造されています。クッキーを信用してはいけません。

署名されたクッキー

上述したように、クッキーは簡単に悪意のあるクライアントによって偽造されています。ボトルは、暗号化操作のこの種のを防ぐために、クッキーに署名することができます。あなたがしなければならないすべては、読み取りまたは設定するクッキーを、そのキー秘密にするたびに秘密のキーワード引数を介して署名キーを提供することです。クッキーが署名されていないか、または署名鍵が一致しない場合、結果として、Request.get_cookie()はNoneを返します。

@route('/login')

def login():

username = request.forms.get('username')

password = request.forms.get('password')

if check_user_credentials(username, password):

response.set_cookie("account", username, secret='some-secret-key')

return "Welcome %s! You are now logged in." % username

else:

return "Login failed."

@route('/restricted')

def restricted_area():

username = request.get_cookie("account", secret='some-secret-key')

if username:

return "Hello %s. Welcome back." % username

else:

return "You are not logged in. Access denied."

自動的に加えて、ボトルをpickleあるいはunpickle署名クッキーに保存されているすべてのデータ。これは、ピクルスのデータが4 KBの制限を超えない限り、クッキーへのピクルス可能なオブジェクトを(だけでなく、文字列)、保存することができます。

警告

署名されたクッキーは暗号化されていません(クライアントはコンテンツを見ることができます)と(クライアントが古いクッキーを復元することができます)コピーして保護されていない。主な目的は、安全のpickle化およびunpickle化すると、クライアント側で秘密情報を格納するのではなく、操作を防ぐためです。

要求データ

ボトルには、Cookie、ヘッダーとグローバル·リクエスト·オブジェクトを介してPOSTフォームデータなどのHTTP関連のメタデータへのアクセスを提供します。このオブジェクトは、いつものように長く、それがコールバック関数内からアクセスされると、現在の要求に関する情報が含まれています。これは、複数の要求が同時に処理され、マルチスレッド環境でも動作します。グローバルオブジェクトスレッドセーフであることができる方法の詳細については、contextlocal参照してください。

注意

ボトルはFormsDictインスタンスで解析されたHTTPメタデータのほとんどが格納されます。これらは通常の辞書と同じように動作しますが、いくつかの追加機能があります。辞書内のすべての値が属性として用意されています。これらの仮想属性は、常に値が欠落している場合でも、Unicode文字列を返します。その場合には、文字列は空です。


FormsDictはMultiDictのサブクラスであり、キーごとに複数の値を格納することができます。標準の辞書のアクセス方法は単一の値のみを返しますが、MultiDict.getall()メソッドは、特定のキーのすべての値のリスト(空かもしれません)を返します。

完全なAPIと機能のリストは、APIセクション(要求を参照)で説明されていますが、最も一般的なユースケースと機能はあまりにも、ここでカバーされています。

クッキー

クッキーはFormsDictとしてBaseRequest.cookiesに格納されています。 BaseRequest?.get_cookie()メソッドは、別のセクションで説明したように署名されたクッキーにアクセスすることができます。この例では、単純なクッキー·ベースのビュー·カウンタを示しています。

from bottle import route, request, response

@route('/counter')

def counter():

count = int( request.cookies.get('counter', '0') )

count += 1

response.set_cookie('counter', str(count))

return 'You visited this page %d times' % count

HTTPヘッダー

クライアントから送信されたすべてのHTTPヘッダー(例えばリファラ、エージェントまたはAccept-Language)をWSGIHeaderDictとBaseRequest.headersを介してアクセス可能に格納されています。 WSGIHeaderDictは、基本的に大文字と小文字を区別しないキーを持つ辞書です。

from bottle import route, request

@route('/is_ajax')

def is_ajax():

if request.headers.get('X-Requested-With') == 'XMLHttpRequest':

return 'This is an AJAX request'

else:

return 'This is a normal request'

クエリ変数

クエリ文字列(/フォーラムのように?ID = 1&ページ= 5)は一般に、サーバーにキー/値ペアの数が少ないを送信するために使用されています。あなたは、文字列全体を取得するためにこれらの値とBaseRequest.query_string属性にアクセスするBaseRequest.query(FormsDict?)を使用することができます。

from bottle import route, request, response

@route('/forum')

def display_forum():

forum_id = request.query.id

page = request.query.page or '1'

return 'Forum ID: %s (page %s)' % (forum_id, page)

フォームデータとファイルのアップロードのPOST

POSTとPUTリクエストのリクエストボディは、さまざまな形式でエンコードされたフォームデータを含めることができます。 BaseRequest?.forms辞書はBaseRequest.filesに格納ファイルのアップロードとBaseRequest.POST一つに両方の辞書を組み合わせて、解析されたテキスト形式のフィールドが含まれています。 3すべてのFormsDictインスタンスで、オンデマンドで作成されます。ファイルのアップロードは、いくつかのメタデータと一緒に特別なcgi.FieldStorageオブジェクトとして保存されます。最後に、BaseRequest?.body経由でファイルライクオブジェクトとして生の身体データにアクセスすることができます。

ここで単純なファイルアップロードフォームの例は、次のとおりです。

from bottle import route, request

@route('/upload', method='POST')

def do_upload():

name = request.forms.name

data = request.files.data

if name and data and data.file:

raw = data.file.read() # This is dangerous for big files

filename = data.filename

return "Hello %s! You uploaded %s (%d bytes)." % (name, filename, len(raw))

return "You missed a field."

Unicodeに関する問題

Python 2ではすべてのキーと値は、バイト文字列です。あなたは、Unicodeが必要な場合は、FormsDict?.getunicode()を呼び出すか、属性アクセスを介して値をフェッチできます。と失敗した場合は空の文字列を返します。どちらの方法で文字列(UTF8デフォルト)をデコードしてみてください。いいえUnicodeErrorをキャッチする必要はありません。

'Göttingen' # An utf8 string provisionally decoded as ISO-8859-1 by the server

>>> request.query.city

'Göttingen' # The same string correctly re-encoded as utf8 by bottle

Python 3ではすべての文字列Unicodeであるが、HTTPはバイトベースのワイヤプロトコルです。サーバは、それらがアプリケーションに渡される前に何らかの形でバイト列をデコードする必要があります。安全側であるためには、WSGIISO-8859-1(別名は、latin1)、後で別のエンコーディングを使用して再エンコードすることができます可逆シングルバイトコーデックを示唆している。ボトルは、そのFormsDict.getunicode()と属性アクセスのためではなく、その他のdict-アクセスメソッドに対して行います。これらは、あなたが望むものはおそらくありませんサーバの実装によって提供変わらない値を返します。

>>> request.query['city']

'Göttingen' # An utf8 string provisionally decoded as ISO-8859-1 by the server

>>> request.query.city

'Göttingen' # The same string correctly re-encoded as utf8 by bottle

あなたは正しくデコードされた値(例えばWTForms用)全体の辞書が必要であれば、再エンコードされたコピーを取得しFormsDict.decode()を呼び出すことができます。

WSGI環境

各BaseRequestインスタンスWSGI環境ディクショナリをラップします。オリジナルはBaseRequest.environに格納されますが、リクエストオブジェクト自体も、辞書のように動作しています。興味深いデータのほとんどは、特別なメソッドや属性を介して公開されていますが、直接WSGI環境変数にアクセスする場合は、そのように行うことができます。

@route('/my_ip')

def show_ip():

ip = request.environ.get('REMOTE_ADDR')

# or ip = request.get('REMOTE_ADDR')

# or ip = request['REMOTE_ADDR']

return "Your IP is: %s" % ip

テンプレート

ボトルはSimpleTemplateエンジンと呼ばれる高速かつ強力な組み込みのテンプレートエンジンが付属しています。テンプレート()関数またはビュー()デコレータを使用することができますテンプレートレンダリングします。あなたがしなければならないすべてのテンプレートとは、キーワード引数としてテンプレートに渡したい変数の名前を提供することです。ここでテンプレートレンダリングする方法の簡単な例は次のとおりです。

@route('/hello')

@route('/hello/<name>')

def hello(name='World'):

return template('hello_template', name=name)

これは、テンプレートファイルhello_template.tplをロードし、名前の変数を設定してそれをレンダリングします。ボトルは。/ views /フォルダまたはbottle.TEMPLATE_PATHリストで指定された任意のフォルダ内のテンプレートを探します。

ビュー()デコレータを使用する代わりに、テンプレート()を呼び出すのテンプレート変数を使用した辞書を返すことができます。

@route('/hello')

@route('/hello/<name>')

@view('hello_template')

def hello(name='World'):

return dict(name=name)

構文

テンプレート構文は、Python言語の周りに非常に薄い層である。その主な目的は、ブロックの正しいインデントを確実にするためのものですので、インデントを気にせずに、テンプレートの書式を設定できます。 SimpleTemplateエンジン:完全な構文を記述するためのリンクをクリックしてください

ここでのテンプレートの例は、次のとおりです。

%if name == 'World':

Hello {{name}}!

This is a test.

%else:

Hello {{name.title()}}!

How are you?

%end

キャッシング

テンプレートは、コンパイル後にメモリにキャッシュされます。テンプレートファイルに加えられた変更は、テンプレートキャッシュをクリアするまでに影響を与えるにはありません。これを行うにはbottle.TEMPLATES.clear()をコールします。キャッシングは、デバッグモードでは無効になっています。

プラグイン

バージョン0.9の新機能。

ボトルのコア機能は、ケースを使用する最も一般的なカバーですが、マイクロフレームワークとしてそれには限界がある。 "プラグイン"が遊びに来る場所です。プラグインは、フレームワークに欠けている機能を追加するサードパーティ製のライブラリを統合する、または単にいくつかの反復作業を自動化します。

我々は、使用可能なプラグインの成長のリストを持っており、ほとんどのプラグインは、アプリケーション間での移植性、再利用できるように設計されています。チャンスはあなたの問題がすでに解決されたことを高く、すぐに使用できるプラグインが存在しています。されていない場合は、プラグイン開発ガイドはあなたを助けるかもしれません。

エフェクトとプラグインAPIは、多様であり、特定のプラグインに依存しています。例えばSQLitePluginプラグインは、dbキーワード引数を必要とするコールバックを検出し、新しいデータベース接続オブジェクトのコールバックが呼び出されるたびに作成されます。これは非常に便利なデータベースを使用できるようになります。

from bottle import route, install, template

from bottle_sqlite import SQLitePlugin

install(SQLitePlugin(dbfile='/tmp/test.db'))

@route('/show/<post_id:int>')

def show(db, post_id):

c = db.execute('SELECT title, content FROM posts WHERE id = ?', (post_id,))

row = c.fetchone()

return template('show_post', title=row['title'], text=row['content'])

@route('/contact')

def contact_page():

''' This callback does not need a db connection. Because the 'db'

keyword argument is missing, the sqlite plugin ignores this callback

completely. '''

return template('contact')

他のプラグインは、スレッドセーフなローカル·オブジェクトを移入し、要求オブジェクトの詳細を変更するには、コールバックによって返されるデータをフィルタ処理したり、完全にコールバックを回避する可能性があります。例えば、 "auth"というプラグインが有効なセッションをチェックし、元のコールバックを呼び出す代わりに、ログインページを返すことができます。正確には何が起こるかはプラグインに依存しています。

アプリケーション全体のインストール

プラグインは、アプリケーション全体または単に追加の機能を必要とするいくつかの特定のルートにインストールすることができます。ほとんどのプラグインは、安全にすべてのルートにインストールされ、その機能を必要としないコールバックにオーバーヘッドを追加しないように十分にスマートであることができます。

私たちは例えばSQLitePluginプラグインを見てみましょう。それだけでデータベース接続を必要とするルートのコールに影響を与えます。他のルートはそのままにしています。このため、我々は追加のオーバーヘッドアプリケーション全体のプラグインインストールすることができます。

プラグインインストールするには、(インストール)を呼び出す最初の引数としてプラグインを使って:

from bottle_sqlite import SQLitePlugin

install(SQLitePlugin(dbfile='/tmp/test.db'))

プラグインはまだルートのコールには適用されません。これがないルートが失われていないことを確認するために延期されます。は、まずプラグインインストールし、変更したい場合は、後でルートを追加することができます。インストールされているプラ​​グインの順序は、しかし、重要である。プラグインデータベース接続を必要とする場合には、まずデータベースプラグインインストールする必要があります。

プラグインアンインストール

あなたは()以前にインストールしたプラグインアンインストールするには、名前、クラス、またはインスタンスを使用することができます。

sqlite_plugin = SQLitePlugin(dbfile='/tmp/test.db')

install(sqlite_plugin)

uninstall(sqlite_plugin) # uninstall a specific plugin

uninstall(SQLitePlugin) # uninstall all plugins of that type

uninstall('sqlite') # uninstall all plugins with that name

uninstall(True) # uninstall all plugins at once

リクエストを処理しながら、プラグインがあっても、実行時に、いつでもインストールおよび削除することができます。これは、いくつかのきちんとしたトリックを(スロー·デバッグインストールしたり、必要なプラグインだけをプロファイリング)を有効にしますが、使い古されてはいけません。たびにプラグインの変更点のリストは、ルートキャッシュがフラッシュされ、すべてのプラグインが再適用されます。

注意

モジュールレベルのインストール()とアンインストール()関数は、デフォルトアプリケーションに影響を与えます。特定のアプリケーション用のプラグインを管理するには、ボトルのアプリケーションオブジェクト上の対応するメソッドを使用しています。

ルート固有のインストール

ルートの適用パラメータ()を使用すると、経路のごく少数にプラグインインストールする場合は、デコレータに便利です。

sqlite_plugin = SQLitePlugin(dbfile='/tmp/test.db')

@route('/create', apply=[sqlite_plugin])

def create(db):

db.execute('INSERT INTO ...')

ブラックリストプラグイン

明示的にルートの数のプラグインを無効にすることができます。ルート()デコレータは、この目的のためのスキップ·パラメータがあります。

sqlite_plugin = SQLitePlugin(dbfile='/tmp/test.db')

install(sqlite_plugin)

@route('/open/<db>', skip=[sqlite_plugin])

def open_db(db):

# The 'db' keyword argument is not touched by the plugin this time.

if db in ('test', 'test2'):

# The plugin handle can be used for runtime configuration, too.

sqlite_plugin.dbfile = '/tmp/%s.db' % db

return "Database File switched to: /tmp/%s.db" % db

abort(404, "No such database.")

スキップ·パラメータは、単一の値または値のリストを受け入れます。あなたはスキップされるプラグインを識別するための名前、クラス、またはインスタンスを使用することができます。一度にすべてのプラグインをスキップする= Trueをスキップして設定します。

プラグインとサブアプリケーション

ほとんどのプラグインは、それらがインストールされたアプリケーションに固有のものです。その結果、彼らはBottle.mount()でマウントされたサブアプリケーションに影響を及ぼすべきではありません。次に例を示します。

root = Bottle()

root.mount('/blog', apps.blog)

@root.route('/contact', template='contact')

def contact():

return {'email': 'contact@example.com'}

root.install(plugins.WTForms())

あなたがアプリケーションをマウントするたびに、ボトルには、サブアプリケーションに転送するすべての要求は、メインアプリケーションプロキシ·ルートを作成します。プラグインデフォルトでは、プロキシ経路この種の無効になっています。結果として、私たちの(架空の)WTFormsプラグインは/コンタクト経路に影響を与えますが、/ブログサブアプリケーションのルートには影響ありません。

この動作は、正気のデフォルトとして意図されていますが、オーバーライドすることができます。次の例は、再活性化し、特定のプロキシの経路のすべてのプラグイン

root.mount('/blog', apps.blog, skip=None)

しかし、思わぬ障害があります:プラグインは単一のルートとして、サブアプリケーション全体を見て、すなわち、プロキシルートは、上記の。サブアプリケーションの個々の経路に影響を与えるためには、明示的にマウントされたアプリケーションプラグインインストールする必要があります。

開発

基礎を学び、独自のアプリケーションを書きたいかと思った時?あなたがより生産的に、役立つかもしれないいくつかのヒントはここにある。

デフォルトアプリケーション

ボトルはボトルインスタンスのグローバル·スタックを維持し、モジュールレベルの関数デコレータのいくつかの既定値としてスタックの一番上を使用しています。ルート()デコレータは、例えば、デフォルトアプリケーションにBottle.route()を呼び出すためのショートカットです。

@route('/')

def hello():

return 'Hello World'

この小さなアプリケーションのために非常に便利で、あなたにいくつかの入力を保存しますが、また、モジュールインポートされるとすぐに、ルートがグローバルなアプリケーションインストールされている、ことを意味します。インポートこの種の副作用を避けるために、ボトルには、アプリケーションを構築するための第二に、より明示的な方法を提供しています。

app = Bottle()

@app.route('/')

def hello():

return 'Hello World'

アプリケーションオブジェクトを分離することも、再利用性、多くを向上させます。他の開発者が安全にモジュールからアプリケーションオブジェクトインポートして、一緒にアプリケーションをマージするBottle.mount()を使用することができます。

代替手段として、あなたはまだ便利なショートカットを使用している間に経路を分離するためにアプリケーション·スタックの使用を行うことができます。

default_app.push()

@route('/')

def hello():

return 'Hello World'

app = default_app.pop()

アプリ()とdefault_app()の両方がAppStackのインスタンスであるとスタックのようなAPIを実装しています。あなたから、必要に応じてスタックにプッシュアプ​​リケーションとポップすることができます。あなたが別のアプリケーションオブジェクトを提供していないサードパーティ製のモジュールインポートしたい場合にも役立ちます。

default_app.push()

import some.module

app = default_app.pop()

モードのデバッグ

初期の開発中に、デバッグモードでは、非常に役立つことがあります。

bottle.debug(True)

このモードでは、ボトルははるかに冗長であり、エラーが発生するたびに有用デバッグ情報を提供します。それはまたあなたの邪魔になるかもしれないいくつかの最適化を無効にし、可能な限り設定ミスについて警告をいくつかのチェックを追加します。

ここで、デバッグモードで変更するものの不完全なリストは、次のとおりです。

デフォルトのエラーページでは、トレースを示しています。

テンプレートキャッシュされません。

プラグインはすぐに適用されます。

ただ本番サーバー上でデバッグモードを使用しないことを確認してください。

リロードオート

開発中に、あなたの最近の変更をテストするためにサーバーをたくさん起動する必要があります。自動リロード機能はあなたのためにこれを行うことができます。あなたは、モジュールファイルを編集するたびに、リロード機能·サーバー·プロセス再起動し、コードの最新バージョンをロードします。

from bottle import run

run(reloader=True)

どのように動作します:メインプロセスサーバを起動するが、メインプロセスを開始するために使用されているのと同じコマンドライン引数を使用して、新しい子プロセスを生成しません。すべてのモジュールレベルのコードは、少なくとも二回実行されます!注意してください。

プロセスos.environ BOTTLE_CHILD?がtrueに設定されていると通常の非リロードアプリケーションサーバとして起動します。すぐにロードされたモジュールの変更のいずれかと同様に、子プロセスは終了し、メイン·プロセスによって再生成された。テンプレートファイルの変更は、リロードをトリガしません。テンプレートキャッシュを無効にするデバッグモードを使用してください。

リロードは、子プロセスを停止する能力に依存している。あなたがsignal.SIGINTをサポートしていないWindowsまたは他のオペレーティングシステムPythonでとKeyboardInterruptが発生している)上で実行されている場合、signal.SIGTERMは子を殺すために使用されています。終了ハンドラやfinally節などは、SIGTERM後に実行されないことに注意してください。

コマンドラインインタフェース

バージョン0.10以降では、コマンドラインツールとしてボトルを使用することができます。

$ python -m bottle

Usage: bottle.py [options] package.module:app

Options:

-h, --help show this help message and exit

--version show version number.

-b ADDRESS, --bind=ADDRESS

bind socket to ADDRESS.

-s SERVER, --server=SERVER

use SERVER as backend.

-p PLUGIN, --plugin=PLUGIN

install additional plugin/s.

--debug start server in debug mode.

--reload auto-reload on file changes.

localhostにポートのペアとデフォルト値:8080 Addressフィールドは、IPアドレスまたはIPアドレスを取ります。他のパラメータは自己説明的であるべきです。

プラグインアプリケーションの両方がインポート式を介して指定されています。これらは、コロンで区切られ、そのモジュール名前空間に評価するのimportパス(例えばpackage.module)および式から構成されています。詳細については、load()を参照してください。ここではいくつかの例は、次のとおりです。

# Grab the 'app' object from the 'myapp.controller' module and

# start a paste server on port 80 on all interfaces.

python -m bottle -server paste -bind 0.0.0.0:80 myapp.controller:app

# Start a self-reloading development server and serve the global

# default application. The routes are defined in 'test.py'

python -m bottle --debug --reload test

# Install a custom debug plugin with some parameters

python -m bottle --debug --reload --plugin 'utils:DebugPlugin(exc=True)'' test

# Serve an application that is created with 'myapp.controller.make_app()'

# on demand.

python -m bottle 'myapp.controller:make_app()''

展開

ボトルは、デフォルトでは、組み込みのwsgirefのWSGIServerで実行されます。この非スレッドHTTPサーバは、開発と早期の生産のための完全にいいのですが、ときに、サーバーの負荷が増大するパフォーマンスのボトルネックになる可能性があります。

パフォーマンスを向上させる最も簡単な方法は、ペーストまたはCherryPyにのようなマルチスレッド·サーバー·ライブラリインストールし、その代わりに、シングルスレッド·サーバの使用するように瓶を伝えることです。

bottle.run(server='paste')

展開:これは、多くの他のデプロイメント·オプションは、別の資料に記載されている

用語集

callback

いくつかの外部アクションが発生したときに呼び出されることであるプログラマのコード。 Webフレームワークコンテキストでは、URLのパスとアプリケーションコードの間のマッピングは、多くの場合、URLごとにコールバック関数を指定することで実現されています。

decorator

別の関数を返す関数は、通常@デコレータ構文を使用して関数変換として適用されます。デコレータについての詳細は、関数定義のためにPythonのドキュメントを参照してください。

environ

ルートの下のすべてのドキュメントに関する情報が保存され、相互参照に使用される構造。環境は、連続失点だけで新機能と変更されたドキュメントを読み、解析する必要がありますので、解析ステージの後のピクルスです。

handler function

いくつかの特定のイベントや状況を処理する関数。 Webフレームワークでは、アプリケーションアプリケーションを構成するそれぞれの特定のURLのコールバックとしてハンドラ関数をアタッチすることにより開発されています。

source directory

そのサブディレクトリを含むディレクトリは、1つのスフィンクスプロジェクトのすべてのソースファイルが含まれています。