2013-05-30 10 views
9

これは私の初めてのpythonでWeb開発を掘り下げています。私の唯一の他の経験はPHPです。以前はフレームワークを使用したことはありませんでした。だから私はこれを非常に威圧的で混乱させるものにしています。CherrypyとJinja2を使い始める

私のNAS用のZFSモニタを作るためにCherryPy/Jinja2を学ぶことに興味があります。私はCherryPy/Jinja2のドキュメントの基本を読みましたが、サンプルがばらばらになり過ぎすぎることがわかりました。これら2つのものを正常にまとめる方法はわかりません。

私が持っているいくつかの質問:

  1. は簡単なチュートリアルがありますが、あなたがCherryPyにとJinja2のがうまく連携させる方法を示していますか?私は、CherryPy/Jinja2のドキュメントや複雑な方法のサンプルのように、単純すぎるサンプルを見つけています。 (例:https://github.com/jovanbrakus/cherrypy-example)。

  2. CherryPyのWebアプリケーションを作成するための標準化された、つまり「期待される」方法はありますか? (例:私のディレクトリ構造はどのように見えますか?静的なものを宣言する方法はありますか?それでも必要ですか?)

  3. 誰にもこれに関する推奨文献がありますか? Pythonのを選ぶ上

答えて

26

おめでとうございます、私はあなたがCherryPyにについてI.

を持っているとしてそれを愛することを学ぶだろうと確信している、私は専門家ではないんだけど、あなたと同じ船に乗ってもいました数日前と私はチュートリアルが少しばらばらになっていることに同意します。

doc pageのようにJinja2を統合するには、HTMLのスニペットがテンプレートファイルであり、パス/templates/index.htmlに保存されている必要があります。また、テンプレートコードサンプルとコントローラサンプルで一致しなかった変数も使用しました。

import cherrypy 
from jinja2 import Environment, FileSystemLoader 
env = Environment(loader=FileSystemLoader('templates')) 

class Root: 
    @cherrypy.expose 
    def index(self): 
     tmpl = env.get_template('index.html') 
     return tmpl.render(salutation='Hello', target='World') 

cherrypy.config.update({'server.socket_host': '127.0.0.1', 
         'server.socket_port': 8080, 
         }) 

cherrypy.quickstart(Root()) 

/templates/index.html:

下記の代わりにCherryPyにとJinja2の

/main.pyを使用して簡単なハロー世界の完全な作業のサンプルです

<h1>{{ salutation }} {{ target }}</h1> 

次に、シェル/コマンドプロンプトで、を使用してアプリを提供してください

python main.py 
そして、あなたのブラウザであなたがうまくいけば、あなたのCherryPyにアプリにJinja2のテンプレーティングを接続するのに役立つことhttp://localhost:8080

でそれを見ることができるはずです。 CherryPyは、軽量で非常に柔軟なフレームワークで、コードやファイル構造を構造化するさまざまな方法を選択できます。

+2

私は問題のあるプロジェクトの構造も分かりませんでした。この記事とリンクは、少し物事を明確にするのに役立ちました。 https://groups.google.com/forum/?fromgroups#!topic/cherrypy-users/L7YXZD_55ec –

+0

ニース!この紹介は、私がCherryPyとMakoを開始するのに十分です。 –

+0

Upvoteしかし、私の問題はNginx http://stackoverflow.com/questions/23359095/how-to-put-cherrypy-wsgi-behind-nginxで続けるので、助けてください。 – Alex

10

アプリケーション構造

まず、プロジェクトの標準ディレクトリ構造について説明します。 CherryPyには必須ではないため、使用するデータレイヤ、フォーム検証、テンプレートエンジンなどは教えられません。それはあなたとあなたの要求に依存します。もちろん、初心者には混乱を招くので、これは大きな柔軟性です。実際のアプリケーションのディレクトリ構造に近いように見えます。

そして、あなたは通常、開発環境でCherryPyはを起動するには、次のん virtual environmentのルートに立っ
.   — Python virtual environment 
└── website — cherryd to add this to sys.path, -P switch 
    ├── application 
    │ ├── controller.py — request routing, model use 
    │ ├── model.py  — data access, domain logic 
    │ ├── view   — template 
    │ │ ├── layout 
    │ │ ├── page 
    │ │ └── part 
    │ └── __init__.py — application bootstrap 
    ├── public 
    │ └── resource — static 
    │  ├── css 
    │  ├── image 
    │  └── js 
    ├── config.py — configuration, environments 
    └── serve.py — bootstrap call, cherryd to import this, -i switch 

cherrydはCherryPyが提案するアプリケーションの実行方法です。

. bin/activate 
cherryd -i serve -P website 

テンプレート化

今度は、テンプレートディレクトリに近づくとそれがどのように見えることができます見てみましょう。ここでは、template inheritanceの素敵なJinja2のの機能を利用するには

. 
├── layout 
│ └── main.html 
├── page 
│ ├── index 
│ │ └── index.html 
│ ├── news 
│ │ ├── list.html 
│ │ └── show.html 
│ ├── user 
│ │ └── profile.html 
│ └── error.html  
└── part 
    └── menu.html 

は、ページの構造を定義するレイアウト、特定のページに充填することができるスロットです。ウェブサイトのレイアウトとメール通知のレイアウトがあるかもしれません。また、別のページにまたがって使用される再利用可能なスニペットもあります。上の構造に対応するコードを見てみましょう。

a runnableというファイルをナビゲートする方が簡単で、実行して再生することもできます。パスは、最初のセクションのツリーのように.で始まります。

ウェブサイト/ config.py

# -*- coding: utf-8 -*- 


import os 


path = os.path.abspath(os.path.dirname(__file__)) 
config = { 
    'global' : { 
    'server.socket_host' : '127.0.0.1', 
    'server.socket_port' : 8080, 
    'server.thread_pool' : 8, 

    'engine.autoreload.on' : False, 

    'tools.trailing_slash.on' : False 
    }, 
    '/resource' : { 
    'tools.staticdir.on' : True, 
    'tools.staticdir.dir' : os.path.join(path, 'public', 'resource') 
    } 
} 

ウェブサイト/ serve.py

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 


from application import bootstrap 


bootstrap() 


# debugging purpose, e.g. run with PyDev debugger 
if __name__ == '__main__': 
    import cherrypy 
    cherrypy.engine.signals.subscribe() 
    cherrypy.engine.start() 
    cherrypy.engine.block() 

Webサイト/アプリケーション/ __ init__.py

ここ

注目すべき部分がありますCherryPyツールは、レンダリングに関連する定型句を避けるのに役立ちますgテンプレート。 CherryPyページハンドラーからdictをテンプレートのデータとともに返すだけでいいです。従来の構成上の原則に従うと、ツール名は、classname/methodname.htmlなどを使用します。 user/profile.html。デフォルトのテンプレートを上書きするには、@cherrypy.tools.template(name = 'other/name')を使用します。あなたはツールを使用して見ることができるように、トップ

# -*- coding: utf-8 -*- 


import os 
import types 

import cherrypy 
import jinja2 

import config 


class TemplateTool(cherrypy.Tool): 

    _engine = None 
    '''Jinja environment instance''' 


    def __init__(self): 
    viewLoader = jinja2.FileSystemLoader(os.path.join(config.path, 'application', 'view')) 
    self._engine = jinja2.Environment(loader = viewLoader) 

    cherrypy.Tool.__init__(self, 'before_handler', self.render) 

    def __call__(self, *args, **kwargs): 
    if args and isinstance(args[0], (types.FunctionType, types.MethodType)): 
     # @template 
     args[0].exposed = True 
     return cherrypy.Tool.__call__(self, **kwargs)(args[0]) 
    else: 
     # @template() 
     def wrap(f): 
     f.exposed = True 
     return cherrypy.Tool.__call__(self, *args, **kwargs)(f) 
     return wrap 

    def render(self, name = None): 
    cherrypy.request.config['template'] = name 

    handler = cherrypy.serving.request.handler 
    def wrap(*args, **kwargs): 
     return self._render(handler, *args, **kwargs) 
    cherrypy.serving.request.handler = wrap 

    def _render(self, handler, *args, **kwargs): 
    template = cherrypy.request.config['template'] 
    if not template: 
     parts = [] 
     if hasattr(handler.callable, '__self__'): 
     parts.append(handler.callable.__self__.__class__.__name__.lower()) 
     if hasattr(handler.callable, '__name__'): 
     parts.append(handler.callable.__name__.lower()) 
     template = '/'.join(parts) 

    data  = handler(*args, **kwargs) or {} 
    renderer = self._engine.get_template('page/{0}.html'.format(template)) 

    return renderer.render(**data) if template and isinstance(data, dict) else data 


def bootstrap(): 
    cherrypy.tools.template = TemplateTool() 

    cherrypy.config.update(config.config) 

    import controller 

    cherrypy.config.update({'error_page.default': controller.errorPage}) 
    cherrypy.tree.mount(controller.Index(), '/', config.config) 

Webサイト/アプリケーション/ controller.py

@cherrypy.exposeを追加する必要はありませんので、また、ツールが自動的にメソッドを公開することに注意してくださいページハンドラはきれいに見え、他のツールと一貫性があります。 json_out。このデモアプリケーションで

# -*- coding: utf-8 -*- 


import datetime 

import cherrypy 


class Index: 

    news = None 
    user = None 


    def __init__(self): 
    self.news = News() 
    self.user = User() 

    @cherrypy.tools.template 
    def index(self): 
    pass 

    @cherrypy.expose 
    def broken(self): 
    raise RuntimeError('Pretend something has broken') 


class User: 

    @cherrypy.tools.template 
    def profile(self): 
    pass 


class News: 

    _list = [ 
    {'id': 0, 'date': datetime.datetime(2014, 11, 16), 'title': 'Bar', 'text': 'Lorem ipsum'}, 
    {'id': 1, 'date': datetime.datetime(2014, 11, 17), 'title': 'Foo', 'text': 'Ipsum lorem'} 
    ] 


    @cherrypy.tools.template 
    def list(self): 
    return {'list': self._list} 

    @cherrypy.tools.template 
    def show(self, id): 
    return {'item': self._list[int(id)]} 


def errorPage(status, message, **kwargs): 
    return cherrypy.tools.template._engine.get_template('page/error.html').render() 

私は作品を扱う方法を静的リソースを証明するために、blueprint CSSファイルを使用していました。 website/application/public/resource/css/blueprint.cssに入れてください。残りはあまり面白くなく、ちょうどJinja2が完全性のためのテンプレートです。

Webサイト/アプリケーション/ビュー/レイアウト/ main.htmlを

<!DOCTYPE html> 
<html> 
    <head> 
    <meta http-equiv='content-type' content='text/html; charset=utf-8' /> 
    <title>CherryPy Application Demo</title> 
    <link rel='stylesheet' media='screen' href='/resource/css/blueprint.css' /> 
    </head> 
    <body> 
    <div class='container'> 
     <div class='header span-24'> 
     {% include 'part/menu.html' %} 
     </div> 
     <div class='span-24'>{% block content %}{% endblock %}</div>  
    </div> 
    </body> 
</html> 

Webサイト/アプリケーション/ビュー/ページ/インデックス/インデックス。HTML

{% extends 'layout/main.html' %} 
{% block content %} 
    <div class='span-18 last'> 
     <p>Root page</p>  
    </div> 
{% endblock %} 

Webサイト/アプリケーション/ビュー/ページ/ニュース/するlist.html

{% extends 'layout/main.html' %} 
{% block content %} 
    <div class='span-20 last prepend-top'> 
    <h1>News</h1> 
    <ul> 
    {% for item in list %} 
     <li><a href='/news/show/{{ item.id }}'>{{ item.title }}</a> ({{ item.date }})</li> 
    {% endfor %} 
    </ul> 
    </div> 
{% endblock %} 

Webサイト/アプリケーション/ビュー/ページ/ニュース/ show.html

{% extends 'layout/main.html' %} 
{% block content %} 
    <div class='span-20 last prepend-top'> 
    <h2>{{ item.title }}</h2> 
    <div class='span-5 last'>{{ item.date }}</div> 
    <div class='span-19 last'>{{ item.text }}</div> 
    </div> 
{% endblock %} 

ウェブサイト/アプリケーション/表示/ページ/ユーザー/ profile.html

{% extends 'layout/main.html' %} 
{% block content %} 
    <div class='span-18'> 
    <table> 
     <tr><td>First name:</td><td>John</td></tr> 
     <tr><td>Last name:</td><td>Doe</td></tr> 
    <table> 
    </div> 
{% endblock %} 

Webサイト/アプリケーション/ビュー/ページ/ error.html

それは404ページです。

{% extends 'layout/main.html' %} 
{% block content %} 
    <h1>Error has happened</h1> 
{% endblock %} 

Webサイト/アプリケーション/ビュー/パート/ menu.html

<div class='span-4 prepend-top'> 
    <h2><a href='/'>Website</a></h2> 
</div> 
<div class='span-20 prepend-top last'> 
    <ul> 
     <li><a href='/news/list'>News</a></li> 
     <li><a href='/user/profile'>Profile</a></li> 
     <li><a href='/broken'>Broken</a></li> 
    </ul> 
</div> 

参照

上記のコードはqooxdoo-website-skeletonのバックエンド部分と密接に行きます。このようなアプリケーションのDebain展開を本格的に行うには、cherrypy-webapp-skeletonが便利です。

+0

テンプレートツールを使用すると、関数内からテンプレートをオーバーライドできますか?たとえば、ほとんどの場合、デフォルトのテンプレート動作が必要だったのですが、特定の条件が満たされている場合は、別のテンプレートパスに切り替える必要があります(https://gist.github.com/anonymous/a0bebdac4245a564c1a5)。 –

+1

@Justinはい。ツールはハンドラをラップするので、ハンドラの副作用がオーバーライドされないように、ハンドラを少し変更する必要があります。 'data = handler(* args、** kwargs)または{}'を 'TemplateTool._render'の最初の行に置くだけでコードが動作します。 – saaj