Comparing and Combining Traversal and URL Dispatch

(改编自Bayle Shank在https://github.com/bshanks/pyramid/commit/c73b4662c9671b5f2c3be26cf088ee983952ab61a上的贡献)。

下面是一个比较URL调度和遍历的示例。

Let's say we want to map

/hello/login to a function login in the file myapp/views.py

/hello/foo to a function foo in the file myapp/views.py

/hello/listDirectory to a function listHelloDirectory in the file myapp/views.py

/hello/subdir/listDirectory to a function listSubDirectory in the file myapp/views.py

使用URL调度,我们可能有:

1
2
3
4
5
6
7
8
9
config.add_route('helloLogin', '/hello/login')
config.add_route('helloFoo', '/hello/foo')
config.add_route('helloList', '/hello/listDirectory')
config.add_route('list', '/hello/{subdir}/listDirectory')

config.add_view('myapp.views.login', route_name='helloLogin')
config.add_view('myapp.views.foo', route_name='helloFoo')
config.add_view('myapp.views.listHelloDirectory', route_name='helloList')
config.add_view('myapp.views.listSubDirectory', route_name='list')

myapp/views.py request.matchdict['subdir']

With traversal, we have a more complex setup:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyResource(dict):
    def __init__(self, name, parent):
        self.__name__ = name
        self.__parent__ = parent

class MySubdirResource(MyResource):
    def __init__(self, name, parent):
        self.__name__ = name
        self.__parent__ = parent

    # returns a MyResource object when the key is the name
    # of a subdirectory
    def __getitem__(self, key):
        return MySubdirResource(key, self)

class MyHelloResource(MySubdirResource):
    pass

def myRootFactory(request):
    rootResource = MyResource('', None)
    helloResource = MyHelloResource('hello', rootResource)
    rootResource['hello'] = helloResource
    return rootResource

config.add_view('myapp.views.login', name='login')
config.add_view('myapp.views.foo', name='foo')
config.add_view('myapp.views.listHelloDirectory', context=MyHelloResource,
                name='listDirectory')
config.add_view('myapp.views.listSubDirectory', name='listDirectory')

In the traversal example, when a request for /hello/@@login myRootFactory(request) , and gets back the root resource. It calls the MyResource instance's __getitem__('hello') MyHelloResource . We don't traverse the next path segment ( ``@@login`), because the `` @ `` means the text that follows it is an explicit view name, and traversal ends. The view name 'login' is mapped to the `` 登录 `` function in ``

/hello/@@foo comes in, a similar thing happens.

When a request for /hello/@@listDirectory comes in, the framework calls myRootFactory(request) , and gets back the root resource. It calls MyRootResource's __getitem__('hello') , and gets back a MyHelloResource 实例。它 does not call MyHelloResource's __getitem__('listDirectory') (由于 @@ 领先 listDirectory myapp.views.listRootDirectory , because the context (the last resource traversed) is an instance of MyHelloResource .

When a request for /hello/xyz/@@listDirectory comes in, the framework calls myRootFactory(request) MyRootResource . It calls MyRootResource's __getitem__('hello') , and gets back a MyHelloResource __getitem__('xyz') MySubdirResource 实例。它 does not 呼叫 __getitem__('listDirectory')MySubdirResource myapp.views.listSubDirectory MyHelloResource MySubdirResource 通过 request.context .

/hello/xyz/abc/listDirectory

如果您愿意,可以将URL调度和遍历(按此顺序)结合起来。因此,我们可以将上面的内容改写为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyResource(dict):
    def __init__(self, name, parent):
        self.__name__ = name
        self.__parent__ = parent

    # returns a MyResource object unconditionally
    def __getitem__(self, key):
        return MyResource(key, self)

def myRootFactory(request):
    return MyResource('', None)

config = Configurator()

config.add_route('helloLogin', '/hello/login')
config.add_route('helloFoo', '/hello/foo')
config.add_route('helloList', '/hello/listDirectory')
config.add_route('list', '/hello/*traverse', factory=myRootFactory)

config.add_view('myapp.views.login', route_name='helloLogin')
config.add_view('myapp.views.foo', route_name='helloFoo')
config.add_view('myapp.views.listHelloDirectory', route_name='helloList')
config.add_view('myapp.views.listSubDirectory', route_name='list',
                name='listDirectory')

http://localhost:8080/hello/foo/bar/@@listDirectory

这更简单易读,因为我们使用URL调度来处理树顶部的硬编码URL,并且我们只对任意嵌套的子目录使用遍历。