Reputation: 14681
I have done my research and did some pattern matching trials but I still can not figure out how to:
Make part of the route optional. e.g.:
/required (/optional/{str}) Here the part in parentheses is optional.
Apply restraints to routing so instead of a wildcard string, it has to match an item from a tuple.
/view_1/ {('opt_a', 'opt_b', 'opt_c' ...)} in this case, if an item from the tuple is matched, it routes if not 404 or FORBIDDEN
How can I achieve these?
Thank you.
Upvotes: 5
Views: 2233
Reputation: 23341
Pyramid does not support optional patterns in a route. The other answer suggests *optional
but this will match much more than what you asked for which was one optional placeholder, and leaves you with no options at the end of the route for more patterns.
config.add_route('name_with_optional', '/required/{optional}/{str}')
config.add_route('name', '/required/{str}')
Now you want to use the same view for both I imagine, since you are thinking of the placeholder as optional. Thus, simply register the view for both cases:
@view_config(route_name='name_with_optional')
@view_config(route_name='name')
def my_view(request):
optional = request.matchdict.get('optional')
The optional
variable will be None
if 'name'
was the matched route pattern.
As for your second question, you can simply create a custom predicate. This could be either on the route or the view (remember that these are separate in Pyramid). The signature for the predicate is different in each case.
A predicate on the route (less common):
def opt_must_contain(info, request):
opt = info['match'].get('opt')
return opt in ('opt_a', 'opt_b', 'opt_c')
config.add_route('my_route', '/view_1/{opt}', custom_predicates=[opt_must_contain])
If this predicate returns False
then another route with the same pattern could be matched (the route is ignored).
A predicate on the view (more common):
def opt_must_contain(context, request):
opt = request.matchdict.get('opt')
return opt in ('opt_a', 'opt_b', 'opt_c')
config.add_route('my_route', '/view_1/{opt}')
@view_config(route_name='my_route', custom_predicates=[opt_must_contain])
def my_view(request):
opt = request.matchdict.get('opt')
In the view we'll know opt
is one of the required options.
Upvotes: 13
Reputation: 12437
In addition to using custom route predicates, you can achieve both things using URL traversal. I wrote a detailed answer in response to your other question.
I believe traversal is a cleaner and "more natural" solution for such use cases.
Upvotes: 0
Reputation: 142256
It's tricky to explain, but what you want is here http://docs.pylonsproject.org/projects/pyramid/en/1.0-branch/narr/hybrid.html - it's not the easiest of reads, but explains what you're after.
Update after further research
Using:
config.add_route('name', 'foo/*optional')
it's possible to receive the remaining path elements as a tuple
Custom predicates can be used to filter url dispatch as described in http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/urldispatch.html?awesome
Upvotes: 3