Routes with trailing slashes in Pyramid

别说谁变了你拦得住时间么 提交于 2019-12-03 13:54:30

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')

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!