I'm writing a cherrypy app and I was wondering what the best way is for structuring my handlers and code for larger applications?
我正在写一个樱桃应用程序,我想知道构建我的处理程序和代码的最佳方法是什么?
I realize assignment is simple trough cherrypy.root, but what are some practices for writing the handlers and assigning them?
我意识到赋值是简单的通过cherrypy.root,但是编写处理程序并分配它们的一些做法是什么?
(Allow me to prove my confusion!) My initial thought is to write a standard handler class that infers a template to run based on the current URL or class/method combination. Then I would assign one instance of that handler multiple times to the path to create pages. I don't see this working however as the recursive references wouldn't work quite right.
(请允许我证明我的困惑!)我最初的想法是编写一个标准的处理程序类,根据当前的URL或类/方法组合推断出要运行的模板。然后我会多次将该处理程序的一个实例分配给创建页面的路径。我不认为这有效,因为递归引用不会正常工作。
So, given the fact that I'm already drawing blanks on how my own source code should look, I'd love some pointers and examples!
所以,鉴于我已经在我自己的源代码应该如何看待空白的事实,我会喜欢一些指针和示例!
Feel free to ask some detailed questions for me to clarify. While there is plenty of cherrypy tutorial material out there, it tends to only scratch the surface.
随意提出一些详细的问题让我澄清一下。虽然有很多樱桃教程材料,但它往往只是划伤表面。
2 个解决方案
#1
5
This question is wildly subjective - but I'll give it a shot.
这个问题非常主观 - 但我会试一试。
-
First of all, always keep database and data code separate to the web code. What I do is have lots of small files with one class each in a
DB/
folder which are all joined together into aBase.py
file, e.g:首先,始终将数据库和数据代码与Web代码分开。我所做的是有很多小文件,每个文件在DB /文件夹中有一个类,它们都连接在一起成为一个Base.py文件,例如:
Web/ Base.py - The main "base" class, which includes the classes in other web files, starts the web server in
Don't forget the__init__
Users.py - The class which includes methods generally from "DB/Users.py" which checks permissions etc before returning (you may wish to add DB-level security later though) ... DB/ Base.py - The main base DB class, includes the other DB classes. Creates new SQLAlchemy/whatever instances and create database schemas if they don't etc. May pay to have database-wide methods here to keep creating connections etc in one place if you decide to change databases later Users.py - The user/password etc DB storage class file ... Templates/ (HTML templates go here) Static/ (Static images/CSS/javscript etc go here)__init__.py
in each module directory of course so python can find the modules in subdirectories -
It doesn't always matter what methods you use for structuring code in my opinion, but be consistent. I write a document up with all my conventions with my justifications for using them and try to follow them up to the point it makes sense to, but as always
a foolish consistency is the hobgoblin of small minds
, as quoting the python style docs :-)在我看来,用于构造代码的方法并不总是重要,但要保持一致。我用我的所有惯例写了一份文件,并说明了我使用它们的理由,并尝试按照它们的意义进行操作,但总是愚蠢的一致性是小思想的大人物,引用python风格的文档: - )
- Try to use classes rather than straight functions. It mightn't matter for small projects, but for anything non-trivial things can become difficult. It's my preference to have many files with a specific purpose and only a single class in a single file except where it makes sense to have multiple
- This one is probably controversial - I usually name my classes
Class
and just reference it by the module name. I'll give an example of Base.py:
This helps to reduce problems when other modules reference each other when importing, asimport Users class Base(Users.Class): def
__init__
(self): Users.Class.__init__
(self)from Users import Users
will conflict ifUsers.py
hasfrom Base import x
so I always reference by module name. This is just a personal preference though, so do what you want :-P
尝试使用类而不是直接函数。对于小型项目来说可能并不重要,但对于任何重要的事情都可能变得困难。我喜欢有许多具有特定用途的文件,并且在一个文件中只有一个类,除非有多个文件有意义
这可能是有争议的 - 我通常将我的类命名为Class,并仅通过模块名称引用它。我将举例说明Base.py:import Users class Base(Users.Class): def __init __(self): Users.Class .__的init __(个体经营) 这有助于减少导入时其他模块互相引用时的问题,因为如果Users.py具有Base导入x,则用户导入用户将发生冲突,因此我始终按模块名称引用。这只是个人偏好,所以你想做什么:-P
Hopefully you should get an idea from this post though.
希望你能从这篇文章中得到一个想法。
#2
10
CherryPy deliberately doesn't require you to subclass from a framework-provided base class so that you are free to design your own inheritance mechanism, or, more importantly, use none at all. You are certainly free to define your own base class and inherit from it; in this way, you can standardize handler construction and configuration via the __init__
method of your class, and via class-level variables and methods.
CherryPy故意不要求您从框架提供的基类继承,以便您可以*设计自己的继承机制,或者更重要的是,根本不使用任何基类。您当然可以*定义自己的基类并继承它;通过这种方式,您可以通过类的__init__方法以及类级变量和方法来标准化处理程序构造和配置。
However, the preferred approach is different. For most web applications, you don't really want to vary the actual construction logic of your handlers, nor do you care much about class-level variables or methods; instead, you want reusable variables and methods per URI or per subtree of URI's or per site, not per class. You tend to vary one set of handlers from another set more by instance configuration (handler metadata) and instance methods (handler logic). Traditional class-based inheritance can do this, but it's a bit of a blunt instrument for that kind of customization.
但是,首选方法是不同的。对于大多数Web应用程序,您实际上并不想改变处理程序的实际构造逻辑,也不关心类级变量或方法;相反,您需要每个URI或URI的每个子树或每个站点的可重用变量和方法,而不是每个类。您倾向于通过实例配置(处理程序元数据)和实例方法(处理程序逻辑)更改另一组处理程序中的一组处理程序。传统的基于类的继承可以做到这一点,但对于这种自定义来说,这是一种钝器。
CherryPy, therefore, is designed to provide this sort of per-resource-set customization that class-based inheritance doesn't do well. It provides this through 1) the design of its configuration system, which allows you to bind metadata to a single URI, a subtree of URI's, a subtree of handlers, or a whole site with the same syntax (see http://docs.cherrypy.org/dev/intro/concepts/config.html for an overview), and 2) the hooks and tools system, which allows you to bind logic to a single URI, a subtree of URI's, a subtree of handlers, or a whole site. See http://docs.cherrypy.org/dev/intro/concepts/tools.html
因此,CherryPy旨在提供这种基于类的继承不能很好地进行的每资源集定制。它通过1)配置系统的设计提供了这一点,它允许您将元数据绑定到单个URI,URI的子树,处理程序的子树或具有相同语法的整个站点(请参阅http:// docs。 cherrypy.org/dev/intro/concepts/config.html概述),以及2)钩子和工具系统,它允许您将逻辑绑定到单个URI,URI的子树,处理程序的子树或者整个网站。请参阅http://docs.cherrypy.org/dev/intro/concepts/tools.html
So, practically: do use normal attributes on cherrypy.root
to build your tree of handlers:
所以,实际上:在cherrypy.root上使用普通属性来构建处理程序树:
def make_app():
root = Root()
root.foo = Foo()
root.bars = BarCollection()
return root
However, don't make Root, Foo and Bar inherit from a common base class. Instead, write independent Tools to do things like "infer templates". That is, instead of:
但是,不要让Root,Foo和Bar从公共基类继承。相反,编写独立的工具来执行“推断模板”之类的操作。也就是说,而不是:
from cherrypy import expose
class Foo(MyAppBase):
@expose()
def index(self, a, b, c):
...
root.foo = Foo(template='foo.html')
write:
from cherrypy import expose, tools
class Foo(object):
@tools.render(template='foo.html')
@expose()
def index(self, a, b, c):
...
root.foo = Foo()
...where 'tools.render' is a CherryPy Tool you have written to look up and apply the given template. This approach will allow you to override the arguments to the Tool in your config file and avoid having to repackage or patch your code:
...'tools.render'是您编写的CherryPy工具,用于查找并应用给定的模板。此方法将允许您覆盖配置文件中工具的参数,并避免重新打包或修补代码:
[/foo/]
tools.render.template = 'foo2.html'
#1
5
This question is wildly subjective - but I'll give it a shot.
这个问题非常主观 - 但我会试一试。
-
First of all, always keep database and data code separate to the web code. What I do is have lots of small files with one class each in a
DB/
folder which are all joined together into aBase.py
file, e.g:首先,始终将数据库和数据代码与Web代码分开。我所做的是有很多小文件,每个文件在DB /文件夹中有一个类,它们都连接在一起成为一个Base.py文件,例如:
Web/ Base.py - The main "base" class, which includes the classes in other web files, starts the web server in
Don't forget the__init__
Users.py - The class which includes methods generally from "DB/Users.py" which checks permissions etc before returning (you may wish to add DB-level security later though) ... DB/ Base.py - The main base DB class, includes the other DB classes. Creates new SQLAlchemy/whatever instances and create database schemas if they don't etc. May pay to have database-wide methods here to keep creating connections etc in one place if you decide to change databases later Users.py - The user/password etc DB storage class file ... Templates/ (HTML templates go here) Static/ (Static images/CSS/javscript etc go here)__init__.py
in each module directory of course so python can find the modules in subdirectories -
It doesn't always matter what methods you use for structuring code in my opinion, but be consistent. I write a document up with all my conventions with my justifications for using them and try to follow them up to the point it makes sense to, but as always
a foolish consistency is the hobgoblin of small minds
, as quoting the python style docs :-)在我看来,用于构造代码的方法并不总是重要,但要保持一致。我用我的所有惯例写了一份文件,并说明了我使用它们的理由,并尝试按照它们的意义进行操作,但总是愚蠢的一致性是小思想的大人物,引用python风格的文档: - )
- Try to use classes rather than straight functions. It mightn't matter for small projects, but for anything non-trivial things can become difficult. It's my preference to have many files with a specific purpose and only a single class in a single file except where it makes sense to have multiple
- This one is probably controversial - I usually name my classes
Class
and just reference it by the module name. I'll give an example of Base.py:
This helps to reduce problems when other modules reference each other when importing, asimport Users class Base(Users.Class): def
__init__
(self): Users.Class.__init__
(self)from Users import Users
will conflict ifUsers.py
hasfrom Base import x
so I always reference by module name. This is just a personal preference though, so do what you want :-P
尝试使用类而不是直接函数。对于小型项目来说可能并不重要,但对于任何重要的事情都可能变得困难。我喜欢有许多具有特定用途的文件,并且在一个文件中只有一个类,除非有多个文件有意义
这可能是有争议的 - 我通常将我的类命名为Class,并仅通过模块名称引用它。我将举例说明Base.py:import Users class Base(Users.Class): def __init __(self): Users.Class .__的init __(个体经营) 这有助于减少导入时其他模块互相引用时的问题,因为如果Users.py具有Base导入x,则用户导入用户将发生冲突,因此我始终按模块名称引用。这只是个人偏好,所以你想做什么:-P
Hopefully you should get an idea from this post though.
希望你能从这篇文章中得到一个想法。
#2
10
CherryPy deliberately doesn't require you to subclass from a framework-provided base class so that you are free to design your own inheritance mechanism, or, more importantly, use none at all. You are certainly free to define your own base class and inherit from it; in this way, you can standardize handler construction and configuration via the __init__
method of your class, and via class-level variables and methods.
CherryPy故意不要求您从框架提供的基类继承,以便您可以*设计自己的继承机制,或者更重要的是,根本不使用任何基类。您当然可以*定义自己的基类并继承它;通过这种方式,您可以通过类的__init__方法以及类级变量和方法来标准化处理程序构造和配置。
However, the preferred approach is different. For most web applications, you don't really want to vary the actual construction logic of your handlers, nor do you care much about class-level variables or methods; instead, you want reusable variables and methods per URI or per subtree of URI's or per site, not per class. You tend to vary one set of handlers from another set more by instance configuration (handler metadata) and instance methods (handler logic). Traditional class-based inheritance can do this, but it's a bit of a blunt instrument for that kind of customization.
但是,首选方法是不同的。对于大多数Web应用程序,您实际上并不想改变处理程序的实际构造逻辑,也不关心类级变量或方法;相反,您需要每个URI或URI的每个子树或每个站点的可重用变量和方法,而不是每个类。您倾向于通过实例配置(处理程序元数据)和实例方法(处理程序逻辑)更改另一组处理程序中的一组处理程序。传统的基于类的继承可以做到这一点,但对于这种自定义来说,这是一种钝器。
CherryPy, therefore, is designed to provide this sort of per-resource-set customization that class-based inheritance doesn't do well. It provides this through 1) the design of its configuration system, which allows you to bind metadata to a single URI, a subtree of URI's, a subtree of handlers, or a whole site with the same syntax (see http://docs.cherrypy.org/dev/intro/concepts/config.html for an overview), and 2) the hooks and tools system, which allows you to bind logic to a single URI, a subtree of URI's, a subtree of handlers, or a whole site. See http://docs.cherrypy.org/dev/intro/concepts/tools.html
因此,CherryPy旨在提供这种基于类的继承不能很好地进行的每资源集定制。它通过1)配置系统的设计提供了这一点,它允许您将元数据绑定到单个URI,URI的子树,处理程序的子树或具有相同语法的整个站点(请参阅http:// docs。 cherrypy.org/dev/intro/concepts/config.html概述),以及2)钩子和工具系统,它允许您将逻辑绑定到单个URI,URI的子树,处理程序的子树或者整个网站。请参阅http://docs.cherrypy.org/dev/intro/concepts/tools.html
So, practically: do use normal attributes on cherrypy.root
to build your tree of handlers:
所以,实际上:在cherrypy.root上使用普通属性来构建处理程序树:
def make_app():
root = Root()
root.foo = Foo()
root.bars = BarCollection()
return root
However, don't make Root, Foo and Bar inherit from a common base class. Instead, write independent Tools to do things like "infer templates". That is, instead of:
但是,不要让Root,Foo和Bar从公共基类继承。相反,编写独立的工具来执行“推断模板”之类的操作。也就是说,而不是:
from cherrypy import expose
class Foo(MyAppBase):
@expose()
def index(self, a, b, c):
...
root.foo = Foo(template='foo.html')
write:
from cherrypy import expose, tools
class Foo(object):
@tools.render(template='foo.html')
@expose()
def index(self, a, b, c):
...
root.foo = Foo()
...where 'tools.render' is a CherryPy Tool you have written to look up and apply the given template. This approach will allow you to override the arguments to the Tool in your config file and avoid having to repackage or patch your code:
...'tools.render'是您编写的CherryPy工具,用于查找并应用给定的模板。此方法将允许您覆盖配置文件中工具的参数,并避免重新打包或修补代码:
[/foo/]
tools.render.template = 'foo2.html'