On Fri, Aug 28, 2015 at 3:01 AM, Petr Blahos <[email protected]> wrote:
On Fri, Aug 28, 2015 at 9:54 AM, Mehdi <[email protected]> wrote:
>> Consider this url:
>> http://mysite.com/customers/137/orders?year=2015&month=5
>> Now in pyramid traversal mechanism, how many queries will be run against
>> database?
>> I guess it would be three:
>> 1. /customers :                             select * from customers
>> 2. /customers/137 :                         select * from customers where
>> id = 137
>> 3. /customers/137/orders?year=2015&month=5: select * from orders where
>> customer_id = 137 and year=:year and month=:month

> traversing your resource tree does not necessarily mean running any queries.
> In
> your example, it wouldn't have to run any queries at all.
> Basically, it is there to bring you to the view and possibly gather some
> information
> on the way.

That's one thing I've been going back and forth about. Should a
resource tree run SQL queries for individual records implied by the
URL? In my case I have a three-level nested structure:
/{incident}/{post}/{attachment} . Each level has a numeric ID and is
1:many to the level on its right. I would not do the collection
queries ("/customers" in Mehdi's example), only the individual-record
queries. The collection queries would either be in the view or in a
resource method.

The advantage of doing individual-record queries ("/customers/137") is
that I can properly raise KeyError if the record doesn't exist. It
feels wrong to raise HTTPNotFound in the view because that's not fully
using the traversal feature. Fetching the record also allows setting
ACLs based on record columns, because I do have a few cases with
record-specific permissions. But running queries during traversal has
several disadvantages:

1) You can't call 'request.resource_path()' without triggering
queries. In my collection view I show a list of links to child pages,
and there's also some peer and ancestor links in the site template and
breadcrumbs. But the main problem is the child links. I don't want to
trigger twenty useless queries for a pageful of links. I tried the
extra positional parameters: 'request.resource_path(context, "137")'
but that returns the URL without a trailing slash, so it's clearly
intended for view names and the like rather than children.

2) Navigating to a grandchild page triggers queries for the ancestor
objects. I usually need a few properties from them anyway, to create
backlinks and show a bit of their information, but by default it
fetches all ancestor columns. I've played around with SQLAlchemy
deferred to fetch the minimal columns needed for backlinks and index
entries, but I end up requiring slightly different columns in
different places so it ends up being rather complex and cumbersome.

3) 'request.resource_path' is not as fiexible as 'request.route_url',
because the latter can easily generate all your internal links both
near and far if you know the route name. But 'request.resource_path'
requires starting from the current context or root, or iterating back
through the ancestors (for breadcrumbs). It seems like a bunch of
unnecessary overhead. And now I have to pass various AJAX URLs to the
template for the front-end developer, so there's even more URLs to
generate.

I finally went back to URL Dispatch because of these. This application
doesn't "need" traversal because the URL structure is fixed.  And I
found a way around the record-specific-permissions issue. The
permitted record IDs are most closely related to the user object, so
rather than fetching the record and finding out who can view and edit
it, I ask the user object which record IDs it can view and edit, and I
build the ACLs from there without fetching the records. That works for
the first level. It doesn't fully work for the second-to-third level
because that depends on a second-level record property. I haven't
decided how to implement that part yet. I may just keep a cached set
of restricted record IDs in global memory or in Redis, and tweak the
ACLs based on whether the current ID is in the restricted set.

I'm also not fully sure how to structure record-specific ACLs and
permissions. For instance, most users can view all incidents, but a
few can only view certain ones, and others can only write certain
ones. Should I do it with a principal like "incident.123.view" and
simple permissions ("incident.view", "incident.edit"). Or should I do
it with complex permissions ("incident.123.view"). But then I run into
a problem that permissions can't be OR: I can't configure a view to
allow "incident.view" OR "incident.123.view", which is what I really
want. So should I do the extra permission-checking in the view? But
that seems wrong.

Also, should I define object-specific permissions ("incident.view"),
or should I double up on simple permissions ("view") and trust that
the ACL will set the right value, even though the same user can view
one object type but not another. In short, where and how should I
specify these record-specific principles-or-permissions?

I am still planning to use traversal in my content-in-a-directory
site. In that case it will have different object types at arbitrary
URLs, so it's a natural for traversal, and it doesn't have complex
ACLs.

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.

Reply via email to