Here's some weird stuff you can do with Pyramid URL dispatch.
You can do the boring thing by associating a route directly with a view callable:
config.add_route('blogentry', '/blog/{id}',
view='mypackage.views.blog_entry_view')
When the above route is matched, for example, when the path of the inbound
URL is blog/123, the view callable defined in the
mypackage.views.blog_entry_view view callable will be called. Yawn.
To spice things up a bit, you can also associate a number of views with a route:
config.add_route('blogentry', '/blog/{id}')
"Wait, what? I don't see any associated view callables there!" That's right, perceptive reader. When you want to associate more than one view with a particular route, the associations are usually done nearer to the view code itself:
from pyramid.view import view_config
@view_config(route_name='blogentry', request_method='GET')
def get_blogentry(request):
...
@view_config(route_name='blogentry', request_method='POST')
def post_blogentry(request):
...
In this case, when the blogentry route is matched during a request, if the
request_method of the request is GET, the get_blogentry view callable
will be invoked. But if the request_method of the request is POST, the
post_blogentry view callable will be invoked. The route_name and
request_method arguments to view_config are view predicate arguments.
When this route matches, for these particular views to be considered, the
route that matched must be blogentry, and the request_method must be GET
for get_blogentry or POST for post_blogentry.
Still kinda boring. Let's add more stuff:
from pyramid.view import view_config
@view_config(route_name='blogentry', request_method='GET', xhr=True)
def get_blogentry_xhr(request):
...
@view_config(route_name='blogentry', request_method='GET')
def get_blogentry(request):
...
@view_config(route_name='blogentry', request_method='POST')
def post_blogentry(request):
...
We added another view callable named get_blogentry_xhr above. This view
will be matched when the blogentry route is matched, when the request
method is GET and when the request is an XMLHttpRequest from JavaScript.
But if a "normal" client invokes a URL that matches the blogentry route, with
either GET or POST one of get_blogentry or post_blogentry will still
be used. The view with the greatest number of predicates that match is
considered "the best match". Just keep tacking on predicates to the view
config to get specific-er and specific-er.
All of the view predicates we've used so far are "built-in" view predicates (there are a list of them in the docs). But we can also define our own view predicates:
def example_dot_com_host(info, request):
if request.host == 'www.example.com:
return True
That's a custom predicate there. It returns True if the hostname is
www.example.com. Here's how we use it:
@view_config(route_name='blogentry', request_method='GET')
def get_blogentry(request):
...
@view_config(route_name='blogentry', request_method='POST')
def post_blogentry(request):
...
@view_config(route_name='blogentry', request_method='GET',
custom_predicates=(example_dot_com_host,))
def get_blogentry_example_com(request):
...
@view_config(route_name='blogentry', request_method='POST',
custom_predicates=(example_dot_com_host,))
def post_blogentry_example_com(request):
...
We added two views above, get_blogentry_example_com and
post_blogentry_example_com. Our custom predicate will return True if the
request hostname is www.example.com. So these views will be found when the
blogentry route matches, when the request method is either GET or POST,
and when the request's hostname is www.example.com. Otherwise, it will
fall back to the next most specific view (either get_blogentry or
post_blogentry).
Anyway, just sayin.