Routes with trailing slashes in Pyramid

2020-06-17 05:33发布

Let's say I have a route '/foo/bar/baz'. I would also like to have another view corresponding to '/foo' or '/foo/'. But I don't want to systematically append trailing slashes for other routes, only for /foo and a few others (/buz but not /biz)

From what I saw I cannot simply define two routes with the same route_name. I currently do this:

config.add_route('foo', '/foo')
config.add_route('foo_slash', '/foo/')
config.add_view(lambda _,__: HTTPFound('/foo'), route_name='foo_slash')

Is there something more elegant in Pyramid to do this ?

3条回答
疯言疯语
2楼-- · 2020-06-17 05:55

Found this solution when I was looking for the same thing for my project

def add_auto_route(config,name, pattern, **kw):
    config.add_route(name, pattern, **kw)
    if not pattern.endswith('/'):
        config.add_route(name + '_auto', pattern + '/')
        def redirector(request):
            return HTTPMovedPermanently(request.route_url(name))
        config.add_view(redirector, route_name=name + '_auto')

And then during route configuration,

add_auto_route(config,'events','/events')

Rather than doing config.add_route('events','/events')

Basically it is a hybrid of your methods. A new route with name ending in _auto is defined and its view redirects to the original route.

EDIT

The solution does not take into account dynamic URL components and GET parameters. For a URL like /abc/{def}?m=aasa, using add_auto_route() will throw a key error because the redirector function does not take into account request.matchdict. The below code does that. To access GET parameters it also uses _query=request.GET

def add_auto_route(config,name, pattern, **kw):
    config.add_route(name, pattern, **kw)
    if not pattern.endswith('/'):
        config.add_route(name + '_auto', pattern + '/')
        def redirector(request):
            return HTTPMovedPermanently(request.route_url(name,_query=request.GET,**request.matchdict))
        config.add_view(redirector, route_name=name + '_auto')
查看更多
欢心
3楼-- · 2020-06-17 06:00

Pyramid has a way for HTTPNotFound views to automatically append a slash and test the routes again for a match (the way Django's APPEND_SLASH=True works). Take a look at:

http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/urldispatch.html#redirecting-to-slash-appended-routes

As per this example, you can use config.add_notfound_view(notfound, append_slash=True), where notfound is a function that defines your HTTPNotFound view. If a view is not found (because it didn't match due to a missing slash), the HTTPNotFound view will append a slash and try again. The example shown in the link above is pretty informative, but let me know if you have any additional questions.

Also, heed the warning that this should not be used with POST requests.

There are also many ways to skin a cat in Pyramid, so you can play around and achieve this in different ways too, but you have the concept now.

查看更多
smile是对你的礼貌
4楼-- · 2020-06-17 06:09

I found another solution. It looks like we can chain two @view_config. So this solution is possible:

@view_config(route_name='foo_slash', renderer='myproject:templates/foo.mako')    
@view_config(route_name='foo', renderer='myproject:templates/foo.mako')
def foo(request):
   #do something

Its behavior is also different from the question. The solution from the question performs a redirect, so the url changes in the browser. In the second form both /foo and /foo/ can appear in the browser, depending on what the user entered. I don't really mind, but repeating the renderer path is also awkward.

查看更多
登录 后发表回答