Cấu trúc ứng dụng
Đầu tiên về cấu trúc thư mục chuẩn của dự án. Không có gì, vì CherryPy không ủy thác nó, nó cũng không cho bạn biết lớp dữ liệu nào, xác thực biểu mẫu hoặc công cụ khuôn mẫu để sử dụng. Đó là tất cả vào bạn và yêu cầu của bạn.Và tất nhiên vì đây là một sự linh hoạt tuyệt vời vì nó gây ra một số nhầm lẫn cho người mới bắt đầu. Đây là cách cấu trúc thư mục ứng dụng thực tế gần giống như thế nào.
. — 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
Sau đó, đứng ở gốc của virtual environment bạn thường làm như sau để bắt đầu CherryPy trong môi trường phát triển. cherryd
là cách đề xuất của CherryPy để chạy một ứng dụng.
. bin/activate
cherryd -i serve -P website
Templating
Bây giờ chúng ta hãy nhìn gần gũi hơn với các mẫu thư mục và những gì nó có thể trông như thế nào.
.
├── layout
│ └── main.html
├── page
│ ├── index
│ │ └── index.html
│ ├── news
│ │ ├── list.html
│ │ └── show.html
│ ├── user
│ │ └── profile.html
│ └── error.html
└── part
└── menu.html
Để khai thác tính năng tuyệt vời Jinja2 của template inheritance, đây là bố cục xác định cấu trúc của một trang, các khe có thể được điền vào một trang cụ thể. Bạn có thể có bố cục cho trang web và bố cục cho thông báo qua email. Ngoài ra còn có một thư mục cho một phần, đoạn trích có thể tái sử dụng được sử dụng trên các trang khác nhau. Bây giờ hãy xem mã tương ứng với cấu trúc ở trên.
Tôi đã thực hiện những điều sau đây cũng có sẵn dưới dạng a runnable để điều hướng các tệp dễ dàng hơn, bạn có thể chạy và chơi với nó. Các đường dẫn bắt đầu bằng .
như trong phần của cây đầu tiên.
website/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')
}
}
website/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()
website/application/__ init__.py
phần đáng chú ý ở đây là một Công cụ CherryPy giúp tránh boilerplate liên quan đến renderin g mẫu. Bạn chỉ cần trả về dict
từ trình xử lý trang CherryPy với dữ liệu cho mẫu. Theo nguyên tắc quy ước trên cấu hình, công cụ khi không được cung cấp với tên mẫu sẽ sử dụng classname/methodname.html
ví dụ: user/profile.html
. Để ghi đè mẫu mặc định, bạn có thể sử dụng @cherrypy.tools.template(name = 'other/name')
. Cũng lưu ý rằng công cụ này cho thấy một phương pháp tự động, do đó bạn không cần phải thêm @cherrypy.expose
trên
# -*- 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)
website/application/controller.py
Như bạn có thể thấy với việc sử dụng công cụ này các trình xử lý trang trông khá sạch sẽ và phù hợp với các công cụ khác, ví dụ: 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()
Trong ứng dụng demo này, tôi đã sử dụng blueprint tệp css, để minh họa cách xử lý tài nguyên tĩnh hoạt động. Đặt nó vào website/application/public/resource/css/blueprint.css
. Phần còn lại là ít thú vị, chỉ cần mẫu Jinja2 cho đầy đủ.
website/application/view/layout/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>
website/application/xem/trang/index/index.html
{% extends 'layout/main.html' %}
{% block content %}
<div class='span-18 last'>
<p>Root page</p>
</div>
{% endblock %}
website/application/xem/trang/news/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 %}
website/application/xem/trang/news/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 %}
trang web/application/view/page/user/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 %}
website/application/xem/trang/error.html
Đó là một trang 404.
{% extends 'layout/main.html' %}
{% block content %}
<h1>Error has happened</h1>
{% endblock %}
website/application/xem/phần/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>
Tài liệu tham khảo
Mã trên đi liền với phần backend của qooxdoo-website-skeleton. Đối với việc triển khai Debain đầy đủ của ứng dụng như vậy, cherrypy-webapp-skeleton có thể hữu ích.
Tôi đã gặp khó khăn trong việc tìm ra cấu trúc dự án tốt và bài đăng này và các liên kết được bao gồm đã giúp làm rõ mọi thứ một chút. https://groups.google.com/forum/?fromgroups#!topic/cherrypy-users/L7YXZD_55ec –
Tốt đẹp! phần giới thiệu này là đủ để tôi bắt đầu với CherryPy và Mako. –
Upvote, nhưng xin vui lòng giúp đỡ, bởi vì vấn đề của tôi tiếp tục với Nginx http://stackoverflow.com/questions/23359095/how-to-put-cherrypy-wsgi-behind-nginx. – Alex