Pyramid Traversal __name__ matching a view name
Asked Answered
L

1

6

In a Traversal pyramid app, how does one handle a resource w/ a __name__ that matches a view's name?

If I wanted to get to the view callable "view" for a Resource, I'd use a URL path like:/foo/bar/view. It traverses the resource_tree as so:

RootFactory(request) => RootFactory
RootFactory['foo']   => Foo
Foo['bar']           => Bar
Bar['view']          => KeyError

...and because it can't traverse past Bar & 'view' is left over, it assumes that 'view' is the view name, and matches to my view callable

@view_config(name='view')
def view(context, request):
    return Response(context.__name__)

To get the URL for that path I'd use request.resource_url(resource, "view").

However, if I had a resource such that Bar.__name__ = "view", how can I resolve a URL for "view" on Foo?

# path: /foo/view
RootFactory(request) => RootFactory
RootFactory['foo']   => Foo  # ideally stop here with view_name="view"
Foo['view']          => Bar.__name__ = "view"
# all parts of path matched so view_name="" and context=Bar

Ideally, in this situation, /foo/view would point to view(Foo, request), and /foo/view/view would point to view(Bar, request) where Bar.__name__ == "view".

Is there a way to handle this without writing detection for collisions between __name__ and view names?

Lanthanide answered 13/5, 2016 at 20:7 Comment(0)
L
0

The solution I wound up at is adding an arbitrary layer of container resources.

Below is an example structure of the resources:

class Foo(object):

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

    def __getitem__(self, key):
        if key == "bar":
            return BarContainer(self, "bar")
        else:
            raise KeyError()

class BarContainer(object):

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

    def __getitem__(self, key):
        return Bar(self, key)

class Bar(object):

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

The question mentions wanting to generate resource URLs to the view callable titled view. With BarContainer this just adds an extra slash:

/{foo}/bar/{bar}/<view_name>    
/a/view          => view(context=Foo(name='a'), request)
/a/bar/view      => view(context=BarContainer(name='bar'), request)
/a/bar/b/view    => view(context=Bar(name='b'), request)
Lanthanide answered 16/5, 2016 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.