What is the difference between View and Route predicates?

121 views
Skip to first unread message

Maxim Avanov

unread,
Jan 28, 2015, 3:45:47 PM1/28/15
to pylons-...@googlegroups.com
Greetings!

I work on a project called Rhetoric which aims to port various Pyramid goodies to Django environment.
I've just completed moving custom View predicates (the ones that can be registered with config.add_view_predicate()) and wonder how they differ from Route predicates. I read the relevant documentation section (http://docs.pylonsproject.org/docs/pyramid/en/latest/narr/hooks.html#view-and-route-predicates), but unfortunately didn't form understanding why it might be useful to have exactly the two.

I would really appreciate it, if someone could explain it to me with an example.

Cheers!

Jonathan Vanasco

unread,
Jan 29, 2015, 10:55:41 AM1/29/15
to pylons-...@googlegroups.com
They don't actually differ at all.  There is really only one "Predicate" object with a specified behavior.   As the docs say "You can use the same predicate factory as both a view predicate and as a route predicate."  So they're really the same thing - a PredicateFactory - just invoked in a different context. The Predicate factories work identical and can be used in either context.

Whether you use a route or a view depends on your needs.  It's worth reading up on the Url Dispatch - http://docs.pylonsproject.org/docs/pyramid/en/latest/narr/urldispatch.html - which probably do the best job of explaining this in the docs.

Off the top of my head:  Some reasons why you apply a predicate to a route, is that it may be necessary for dealing with route-matching rules, or allow you to dispatch a single URL to different views depending on the request method.  Some reasons why you might apply predicates to a view, are that it can allow you to register different renderers to a single view callable. Those are just some of the many reasons.

Michael Merickel

unread,
Jan 29, 2015, 2:43:41 PM1/29/15
to Pylons
On Thu, Jan 29, 2015 at 9:55 AM, Jonathan Vanasco <jona...@findmeon.com> wrote:
> They don't actually differ at all. There is really only one "Predicate"
> object with a specified behavior. As the docs say "You can use the same
> predicate factory as both a view predicate and as a route predicate." So
> they're really the same thing - a PredicateFactory - just invoked in a
> different context. The Predicate factories work identical and can be used in
> either context.

This actually isn't true. I'm having trouble finding the docs you've
referenced. They solve different problems but have a very similar api
and semantics.

Pyramid matches a url in 3 steps.

1) Find a matching route.
2) Find a context.
3) Find a view.

When matching a route, the first one that matches wins and if it
doesn't match then we continue in order to the next route in the list,
and see if it matches. Predicates, and the pattern, control whether
this is the route we will use. This predicate receives "info" and
"request" objects. It is "info" because the route is not matched yet,
so you cannot inspect request.matchdict. You can only inspect
info['match'].

http://docs.pylonsproject.org/docs/pyramid/en/latest/narr/urldispatch.html#custom-route-predicates

We aren't really talking about matching a context here so don't worry about it.

When finding a view we now know the route and the context. So the
predicate receives a "context" and "request". They follow basically
the same api because most of the default predicates do not need the
first argument and only bother inspecting the request.

There may even be some bugs here in Pyramid but this is how it works.
Feel free to open any issues.

The route predicates are useful if you have potentially conflicting
routes like '/{catchall:.*}' and '/foo'. You can either re-order the
routes so foo is tested first, or you can add a predicate to the
catchall route requiring the info['match']['catchall'] != 'foo'.
Things escalate in complexity from there.

Most of the time, however, you are thinking about multiple views
attached to a route. Such as request_method='GET' vs
request_method='POST'. Your first instinct may be to attach these to
different routes but then the route name must be different per route.
So instead you have the route match and then add the predicates to the
view.

Jonathan Vanasco

unread,
Jan 29, 2015, 2:57:16 PM1/29/15
to pylons-...@googlegroups.com

On Thursday, January 29, 2015 at 2:43:41 PM UTC-5, Michael Merickel wrote:
This actually isn't true. I'm having trouble finding the docs you've
referenced. They solve different problems but have a very similar api
and semantics.

That was copy/pasted from the narrative docs, which he linked to above.


====================

The __call__ method of a predicate factory must accept a resource (context) and a request, and must return True or False. It is the "meat" of the predicate.

You can use the same predicate factory as both a view predicate and as a route predicate, but you'll need to call add_view_predicate and add_route_predicateseparately with the same factory.

====================
 

Michael Merickel

unread,
Jan 29, 2015, 3:06:35 PM1/29/15
to Pylons
On Thu, Jan 29, 2015 at 1:57 PM, Jonathan Vanasco <jona...@findmeon.com> wrote:
> The __call__ method of a predicate factory must accept a resource (context)
> and a request, and must return True or False. It is the "meat" of the
> predicate.
>
> You can use the same predicate factory as both a view predicate and as a
> route predicate, but you'll need to call add_view_predicate and
> add_route_predicateseparately with the same factory.

Okay, I was worried as I was typing that something was amiss that I
hadn't found yet (hence the open an issue comment).

Basically, the docs are wrong about this and what I said is correct. I
hope that helps. My explanation should make sense as well. There is no
context when matching a route because traversal has not occurred yet,
and the default predicates available on routes and views are not the
same. They are documented in their respective apis (config.add_view vs
config.add_route).

Jonathan Vanasco

unread,
Jan 29, 2015, 3:44:01 PM1/29/15
to pylons-...@googlegroups.com
for tracking purposes, i created a stub issue for the docs referencing this thread

Maxim Avanov

unread,
Jun 2, 2015, 10:33:59 AM6/2/15
to pylons-...@googlegroups.com
Hi guys! I am sorry for a very late response. It all makes sense now, thank you.
Reply all
Reply to author
Forward
0 new messages