详解 repoze.bfg traversal

来源:互联网 发布:如何使用数据有效性 编辑:程序博客网 时间:2024/05/18 02:18

Traversal

__getitem__

Traversal就是在一个hierarchy对象树上行走. 这个对象树叫做 model graph. Model Graph由容器节点和叶节点构成. 容器和叶只有一个区别, 那就是容器节点有getitem方法, 而叶节点没有. 另外一个重要规则是, 容器节点被期待返回子节点或者raise一个KeyError. 这个exception非常重要, 因为当BFG在路径未穷尽时终止了行走(Terminated by KeyError), 路径的最后一截将被当作view name 而这正是我们需要的行为. 举例: 试想一个容器UserFolder他的getitem是返回folder里面的对象, 有方法getitem(self,id) 这时的请求路径为 /userfolder/id(1,2,3….). 而为了在UserFolder上加item, 通常的路径写法是/userfolder/adduser, 这时getitem传入的是"adduser"这个串, 如果id是个int, 那么在这里的raise KeyError就自然的终止了行走, adduser就被当作view name, 我们的本意也是想调用这个view callable, 而userfolder是adduser要处理的context. 一切符合自然.

 

__parent__, __name__

在traversal模式下, 任何model graph中的节点对象都要有__parent__, __name__属性, BFG称这种对象为location-aware. 对于根节点, __parent__=__name__=None

这两个属性不必定义在构造器中, 可以在view callable中处理增加对象时刻对新对象赋予属性, 比如下面的增加wiki页面代码:

 
有Exception吗?

没有, 虽然在BFGSite的源代码中子对象看起来都没有name和parent属性, 根据作者的邮件回复, BFGSite是继承repoze.folder.Folder来的, 而这个父类在__setitem__的方法中设置了这两个属性, 所以子类就没有再手动赋值了. 同时作者指出, 如果不赋值, 那么代码中用到 repoze.bfg.url.model_url方法的都会失败.

Using Model Interfaces

先看一个典型的view 指示符:

 


它在说这么一句话, 如果Traversal 完成时, 有如下的结果:
view name: hello.html (见第一段的Traversal描述)
context: Hello的实例
相应的view callable就是views.py中的hello_world(函数或类带__call__).

这段application registry代码将某个数据模型类(model class)Hello和处理代码(hello_world)联系起来. 我们用view callable 来处理这个数据. 关键点在于这个类级别的数据模型. 如果数据模型是一个类级别的东西, 那么view callable 和他之间还是带有紧耦合的味道. 如果我们今后在数据模型上有变动, 就不太灵活. 根据实际情况的复杂度, 你可以使用模型接口model interface来和view callable组合. 好处是一个model interface 可以对应不同的类, 只要他们宣称实现了接口.

(原文: Any time a model that is determined to be the context provides this interface (IHello), and a view named hello.html is looked up against it as per the URL, the .views.hello_world view will be invoked.)

原理

实现接口的model instance

 

这个model由两样东西组成: BlogEntry类定义了model构造器, 和一个interface attached 到这个类上. 注意用词: attach, 这里Interface被看成一个副标题, 起到tag模型的作用. 他给此模型打上了IBlogEntry的标签. (和Blog用tag来快速分类一样).