traversal: resource vs domain model?

43 views
Skip to first unread message

Jasper van den Bosch

unread,
Mar 5, 2012, 3:27:33 PM3/5/12
to pylons-...@googlegroups.com
I have a question for the traversal users: 

do you 

a) load your model from data (i.e. sqla) and add the resource properties (request, __parent__) in the parent?

or

b) have a separate domain model class and a resource class that wraps the former with the above properties?
(i.e. BlogModel and BlogResource)

B seems to be the cleaner version if you have a non-http API as well, but A is clearly simpler.

Thanks for sharing your experience.

Jasper

-- 
jas...@ilogue.com

I'd love to see your attachment, but please use OpenDocument, not a proprietary format like docx. It's an international standard, endorsed by the EU, and implemented in many office suites, such as LibreOffice, and commercial products from Oracle, Sun, IBM and Microsoft (from 2007).

Thomas G. Willis

unread,
Mar 5, 2012, 5:05:12 PM3/5/12
to pylons-...@googlegroups.com
I can only speak for me and my preferences. 

I have a domain model and a Resource Model(i guess that is what it is)

The resource model is similar to the domain model but there are differences because they both serve different purposes. 

I use the domain model for persistence and retrieval, and I use the resource model to provide access to the domain model OR expose other services to the views, sometimes a resource model objects serves both purposes, other times the resource is mostly wrapping what's on the domain model. 

I have no idea if I'm doing it right. But my unit tests still pass :)

Daniel Nouri

unread,
Mar 5, 2012, 7:13:11 PM3/5/12
to pylons-...@googlegroups.com, Jasper van den Bosch
On Mon, Mar 5, 2012 at 9:27 PM, Jasper van den Bosch <jap...@gmail.com> wrote:
> I have a question for the traversal users:
>
> do you
>
> a) load your model from data (i.e. sqla) and add the resource properties
> (request, __parent__) in the parent?

There's no reason your models can't just implement __parent__ and
__name__ as properties themselves. These have nothing to do with
HTTP. (No need to know about the request for traversal!)

An example using SQLAlchemy:
https://github.com/Pylons/Kotti/blob/master/kotti/resources.py#L108


--
http://danielnouri.org

Mike Orr

unread,
Mar 5, 2012, 7:56:32 PM3/5/12
to pylons-...@googlegroups.com

So how would you apply this to a normal SQLAlchemy database, that may
have the concept of name and parent but not in the resource structure?
In particular, an ordinary 1:many relationship where the parent has
several children with a backref to itself, but not using the words
"name" and "parent".

class Main(Base):
id = sa.Column(sa.types.Integer, nullable=False, auto_increment=True)

subs = orm.relationship("Sub", backref="main")

class Sub(Base):
id = sa.Column(sa.types.Integer, nullable=False, auto_increment=True)
main_id = sa.Column(sa.types.Integer, sa.ForeignKey("Main.id"),
nullable=False)

In this case, the 'id' fields can serve as the .__name__, converting
them to a string if necessary. And the 'main' backref is equivalent to
.__parent__. So would the name and parent simply return these
properties? Do we need to do anything to prevent unnecessary queries
for parent?

For large tables, I generally defer the fields that are only used on
the details page and searching -- i.e., not on index pages -- in a
deferral group called 'details'. So if you fetched a Sub and referred
to its parent (probably wanting only the ID and title fields for a
hyperlink, and perhaps a date for sorting), only the fields used
'everywhere' would be loaded. I guess that would "just work" in a
Resource scenario.

Of course, when fetching a sub, there's no place in the API to specify
whether you'll be wanting all its detail fields, unless you query the
database directly, in which case you can't go through the resource
tree.

--
Mike Orr <slugg...@gmail.com>

Daniel Nouri

unread,
Mar 5, 2012, 8:04:48 PM3/5/12
to pylons-...@googlegroups.com, Mike Orr

Yes, they would.

> Do we need to do anything to prevent unnecessary queries
> for parent?

After you traversed down to that item, __parent__ will likely already
be in the SQLA identity map cache, so going up back up to the
parent(s) shouldn't cost you any queries.


Dividing your db fields into 'details' and not sounds like a good idea.


--
http://danielnouri.org

Mike Orr

unread,
Mar 5, 2012, 8:24:01 PM3/5/12
to Daniel Nouri, pylons-...@googlegroups.com

OK. Any tips for attaching an ACL to them? Especially in the case
where permissions are record-specific. For instance, I have a
situation where one group can view and edit all records, another group
can only view, a third set of users (not a group) can view/edit only
this record or a few records, and a fourth set of users can view this
record or a few records but not edit them. Would I just specify:

[(ALLOW, "g:manager1", "view"),
(ALLOW, "g:manager1", "edit"),
(ALLOW, "g:manager2", "view"),
(ALLOW, "user1", "view"), #... user2, user3 ...
(ALLOW, "user1", edit"), # ... user2, user3...
(ALLOW, "user4", "view), # ... user5, user6..
].

How do these interact with the permission arg in the view
configuration, and with the strings coming from the authenticator?

What does a DENY element mean, and how does it interact with the view
config? Does ALLOW mean this permission string is included, and deny
means it's excluded? So the permission arg causes a check whether that
string is excluded? Why would you need DENY at all then if the default
is deny?

--
Mike Orr <slugg...@gmail.com>

Daniel Nouri

unread,
Mar 6, 2012, 4:50:30 AM3/6/12
to Mike Orr, pylons-...@googlegroups.com
On Tue, Mar 6, 2012 at 2:24 AM, Mike Orr <slugg...@gmail.com> wrote:
> OK. Any tips for attaching an ACL to them? Especially in the case
> where permissions are record-specific. For instance, I have a
> situation where one group can view and edit all records, another group
> can only view, a third set of users (not a group) can view/edit only
> this record or a few records, and a fourth set of users can view this
> record or a few records but not edit them. Would I just specify:
>
>   [(ALLOW, "g:manager1", "view"),
>    (ALLOW, "g:manager1", "edit"),
>    (ALLOW, "g:manager2", "view"),
>    (ALLOW, "user1", "view"),    #... user2, user3 ...
>    (ALLOW, "user1", edit"),    # ... user2, user3...
>    (ALLOW, "user4", "view),   # ... user5, user6..
>    ].

For those groups (and users) that have permissions globally ("can
view/edit all records"), you can put the entries at the root. With
the standard ACLAuthorizationPolicy, it'll get inherited down the
traversal path to all children records:

root.__acl__ = [


(ALLOW, "g:manager1", "view"),
(ALLOW, "g:manager1", "edit"),
(ALLOW, "g:manager2", "view"),

]

The entries that control access to individual records are attached to
exactly those instances:

bobsfolder.__acl__ = [(ALLOW, "bob", ("view", "edit"))]

> How do these interact with the permission arg in the view
> configuration, and with the strings coming from the authenticator?

The authenticator will provide user and group names like "bob" and
"g:manager2". The view permissions correspond to "view" and "edit"
here.

> What does a DENY element mean, and how does it interact with the view
> config?  Does ALLOW mean this permission string is included, and deny
> means it's excluded? So the permission arg causes a check whether that
> string is excluded? Why would you need DENY at all then if the default
> is deny?

I haven't ever used DENY, but I suppose it's useful for when you want
to take away permissions down the path. Imagine if Bob wanted his
home folder not to be readable by "g:manager2", he could use a "deny"
ACE to block the inheritance.


--
http://danielnouri.org

Thomas G. Willis

unread,
Mar 6, 2012, 7:58:52 AM3/6/12
to pylons-...@googlegroups.com
Using DENY is handy for stuff like enforcing not being able to "like" your own posts.
Reply all
Reply to author
Forward
0 new messages