strategies for multiple "similar" routes to a single view

29 views
Skip to first unread message

Jonathan Vanasco

unread,
Oct 15, 2014, 2:07:56 PM10/15/14
to pylons-...@googlegroups.com
i'm using url dispatch , and I have some routes that begin with this:

      "/by/{username:\w+}"

i now need to support 'id' based urls as well.  e.g.

      "/by/{userid:\-\d+}"

the regexes are actually more complicated, and defined elsewhere.  

there is an approach i think I'd like to pursue, and I think a custom route factory might be the solution -- but i'm not sure.  hoping someone can point me in the right direction (or offer a better idea).

1.  I'd like to reference an externally defined regex pattern, instead of redefining it (multiple times) in my routes.py.   basically, i'd like to tie in the validation + routing regexes to avoid potential errors in development.

2. i'd like to define a single route, with a single 'identifier' in the route declaration -- and to then process it to augment or redefine the matchdict to contain the specific matched identifier.

e.g.

          route: "/by/{identifier}"
          url a :  /by/-123 => matchdict = {'identifier': '-123', 'userid': '-123'}
          url a :  /by/example=> matchdict = {'identifier': 'example', 'username': 'example}






    

Michael Merickel

unread,
Oct 15, 2014, 2:28:59 PM10/15/14
to Pylons
When defining a route, there are several hooks available to you to
configure custom behaviors.

1) The route pattern.
2) Route predicates.
3) Route factory.

You basically touched on all of these in your examples. It's usually
advantageous to have a single route, so let's ignore the pattern
options. Similarly you can do custom code in the predicates but that's
shoe-horning side-effects into the predicates which is not a good
match.

I'd recommend using a factory specific to that route. You can do cool
things in that factory like inspect/modify the matchdict. Views
attached to that route can then still expect a particular format for
the matchdict and even define *view* predicates that dispatch to
different views based on the matchdict.

On the flip side you can use a pregenerator on that route to make
generation easy. For example, request.route_url('by', userid=50) and
request.route_url('by', username='bob') would both invoke the
pregenerator that inspects the kwargs and converts
kwargs['identifier'] = '-' + kwargs.pop(userid) versus
kwargs['identifier'] = kwargs.pop('username').

Anyway I think you already know how to solve your problem so my ideas
may just reinforce what you were already thinking.

- Michael
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to pylons-discus...@googlegroups.com.
> To post to this group, send email to pylons-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/pylons-discuss.
> For more options, visit https://groups.google.com/d/optout.

Jonathan Vanasco

unread,
Oct 15, 2014, 2:49:08 PM10/15/14
to pylons-...@googlegroups.com
Thanks!  It looks like Route Factory is what I want.


I'll look up some examples in public Pyramid projects and blogs later.

I didn't realize that I could affect the dict with custom predicates.  It was pretty easy to make a temporary prototype with that, after knowing where to look.

Michael Merickel

unread,
Oct 15, 2014, 3:02:43 PM10/15/14
to Pylons
Predicates should return True or False. They have no sense of
locality, so if you mess with the request and return True, and another
predicate returns False then you have screwed up the request for some
subsequent route that may match. This is obviously not ideal, but will
work in 95% of apps.

The factory is invoked *after* the route is matched, which means this
is not a problem.

def parse_identifier(identifier):
return None, None

def user_by_factory(request):
type, value = parse_identifier(request.matchdict['identifier'])
if type is None:
raise HTTPNotFound

request.matchdict[type] = value

config.add_route('by', '/by/{identifier}', factory=user_by_factory)

The return-value of the factory is request.context, so in this case it
will be None. Other times you'd return an object with ACLs and other
useful information for your views and security system to use.

Jonathan Vanasco

unread,
Oct 15, 2014, 3:56:19 PM10/15/14
to pylons-...@googlegroups.com
wow. thanks.  that is a much cleaner explanation than the docs.

converting to a factory was ridiculously simple!
Reply all
Reply to author
Forward
0 new messages