this confuses me a bit. traversal is, in general, a bit _less_ flexible
than URL dispatch as far as having resources live "anywhere" in an
application. it's much easier to map two different URL patterns to the
same view than it is to construct two different traversal paths to the
same resource.
> But I almost feel that the parts between<Blog> and<BlogPost>
> in my tree are better expressed as a URL Dispatch style patterns than
> by creating resources,
i tend to agree.
> specially if resolving the resources means a
> roundtrip to the database at every single step:
>
> /blog
> DB do we have an object named "blog"? yes, it's a BlogResource
> /blog/archive
> BlogResource objects have an implicit child called "archive"
> /blog/archive/2011
> DB Does this particular BlogResource "blog" have posts for the year
> 2011?
> /blog/archive/2011/01
> DB Does this particular BlogResource "blog" have posts for the month
> 2011/01?
> /blog/archive/2011/01/29
> DB Does this particular BlogResource "blog" have posts for the month
> 2011/01/29?
> /blog/archive/2011/01/29/my-post-about-pyramid
> DB Does this particular BlogResource "blog" have a
> BlogPostResource 2011/01/29/my-post-about-pyramid?
yup, this pretty much describes what would be happening.
> Of course I could also stop anywhere in between , where I would want
> to see a list of BlogPosts matching that particular date range. But It
> seems crazy that I should have 5 different calls to the DB to resolve
> that path, when I would probably want, once I know I have traversed to
> a Blog object, to try to resolve the rest of the path with a single
> call to the DB.
>
> but I would love to not have to worry about the view infrastructure,
> because one of the things I liked about Zope is being able to declare
> views after the fact, completely separate from the resource objects,
> so I would imagine I could have "/blog/json" or "/blog/archive/atom"
> or "/blog/archive/2011/01/29/my-post-about-pyramid/edit" all being
> valid URL as well, which should match to explicit views and not just
> resources.
again, i'm a bit confused. zope is all about traversal, so the examples
you give above are quite different from each other. the first would
likely be a "json" view on the "blog" resource, the second an "atom"
view on the "archive: resource, the final would be an "edit" view on the
blog post resource. views are _always_ in the context of a resource
with zope.
> QUESTIONS:
>
> - Am I thinking too hard, and should I just use URL Traversal instead?
i suspect yes.
> - Should I just do what ZODB does and implement the full resource
> hierarchy explicitely in my DB?
you don't have to, but it'd make things conceptually a bit simpler (than
using traversal and not doing so, that is; url dispatch would be simpler
yet). but it does make the content more "placeful", so you'll still
have to jump through some hoops if you want the same blog post to be
reachable from two different urls.
> - Is there a way to create hybrid URLDispatch + Traversal application
> when the traversal happens first, and a resource can trigger a route
> match on the remaining portion of the URL?
yep: http://docs.pylonsproject.org/projects/pyramid/dev/narr/hybrid.html
-r
On 01/30/2011 09:04 AM, Wade Leftwich wrote:
> If you want to stick with Traversal, don't forget that you have
> request.subpath available to you. For the path "/blog/archive/
> 2011/01/29/my-post-about-pyramid", you could have an Archive context
> whose default (unnamed) view would be called with a request that
> included request.subpath = ['2011', '01', '29', 'my-post-about-
> pyramid'].
Other traversal-based strategies:
- - an 'archive' view registered for the blog context (assuming you don't
otherwise need the 'archive' context).
- - add non-persistent placeholder objects to your app to take advantage
of traversal's use of '__getitem__'. This solution allows you write
views for the "transient" context classes, even though they aren't in
your database. E.g., something like:
- --------------------------- %< ---------------------
class Blog:
...
def __getitem__(self, key):
if key == 'archive':
return Archive(self)
return super(Blog, self).__getitem__(key)
class Archive:
__name__ = 'archive'
YEARS = range(2010, 2100)
def __init__(self, blog):
self.__parent__ = self.blog = blog
def __getitem__(self, key):
try:
year = int(key)
except TypeError:
raise KeyError(key)
if year not in self.YEARS:
raise KyeError(key)
return ArchiveYear(self, year)
class ArchiveYear:
__name__ = 'archive'
MONTHS = range(1, 12)
def __init__(self, archive, year):
self.__parent__ = archive
self.__name__ = str(year)
self.blog = archive.blog
self.year = year
def __getitem__(self, key):
try:
mnnth = int(key)
except TypeError:
raise KeyError(key)
# or, return self.blog.entries[key]
if month not in self.MONTHS:
raise KeyError(key)
return ArchiveMonth(self, month)
class ArchiveMonth:
__name__ = 'archive'
MONTHS = range(1, 12)
def __init__(self, year, month):
self.__parent__ = year
self.__name__ = str(month)
self.blog = year.blog
self.month = month
def __getitem__(self, key):
return self.blog.entries[key]
- --------------------------- %< ---------------------
> The view would then call a method on the Archive context using
> arguments constructed from the request.subpath. The Archive would in
> turn make a single call to Mongo. A path like '/blog/archive/2011/01'
> would require some logic in the view, to choose a different Archive
> method and a different template to show a listing of posts for
> January, or perhaps redirect to /blog/month/2011/01 .
>
> So if you are using Traversal in this way, the logic for parsing the
> path lives in the view and/or the context. With URL Dispatch it's in
> the configuration.
Agreed. I find the traversal stuff much easier to test on this account.
The fact that I find it easier to think about is likely due to the warp
in my brain from years of heavy Zope usage. ;)
Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 tse...@palladion.com
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk1FjgoACgkQ+gerLs4ltQ4fuwCdE04ygTijKNcWg6mLsLK8Ruq3
ewUAoL+DDXtoQk9+idz4PrwS0E2DaQbJ
=g74T
-----END PGP SIGNATURE-----
Are you traversing each level of the date here, or using a subpath from archive?
It seems like extra overhead to create a temporary Year class and
Month class just to traverse through them. What are you gaining?
I'm thinking of making a CMS site with articles embedding nested
comments. Chris suggested making the article a repoze.folder.Folder
subclass. I said it seems funny to think of an artlcle as a folder. He
said he makes almost everything folders nowadays, as it makes it
easier to both use the object and traverse through it. Could
ArchiveYear and ArchiveMonth be made into Folder subclasses to factor
away some of the code?
--
Mike Orr <slugg...@gmail.com>
On 01/30/2011 01:21 PM, Mike Orr wrote:
> On Sun, Jan 30, 2011 at 8:25 AM, Wade Leftwich wrote:
>> Actually a bit more in keeping with the spirit of Traversal, and again
>> keeping your calls to Mongo to a mininum, would be something like
>> this:
>>
>> /blog/month/2011/01/29/my-post-about-pyramid would do this:
>>
>> archive = Blog['archive']
>> year = archive['2011'] = archive.__getitem__('2011') = Year(y=2011)
>> month = year['01'] = year.__getitem__('01') = Month(y=2011, m=1)
>> day = month['29'] = month.__getitem__('01') = Day(y=2011, m=1, d=29)
>> post = day['my-post-about-pyramid'] = day.__getitem__('my-post-about-
>> pyramid') = Post(y=2011, m=1, d=29, slug='my-post-about-pyramid')
>> ... and the default view for Post would be to query Mongo
>>
>> This would handle shorter paths in a natural way -- e.g. '/blog/month/
>> 2011/01' would map to the default view for Month(y=2011, m=1), which
>> would call Post.list_posts_for_month() .
>
> Are you traversing each level of the date here, or using a subpath from archive?
>
> It seems like extra overhead to create a temporary Year class and
> Month class just to traverse through them. What are you gaining?
One advantage: this strategy allows registering views against those
transient classes, which means that in the "reusable app" scenario the
re-using app can override those views selectively.
Another advantage: the logic is in the code, not in per-deployment
configuration, which makes it unit-testable.
> I'm thinking of making a CMS site with articles embedding nested
> comments. Chris suggested making the article a repoze.folder.Folder
> subclass. I said it seems funny to think of an artlcle as a folder. He
> said he makes almost everything folders nowadays, as it makes it
> easier to both use the object and traverse through it. Could
> ArchiveYear and ArchiveMonth be made into Folder subclasses to factor
> away some of the code?
That would makes sense if you actually want to *store* the entries
inside the archive/year/month tree (a perfectly reasonable strategy).
Making the *entry* a folder would make sense if you wanted to store
other items (images, audio / video clips, tarballs, PDFs) inside it.
Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 tse...@palladion.com
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk1G5xgACgkQ+gerLs4ltQ78OACfSx7iwBQjabB/GYwpG4qlD/Q0
LOIAn02erOioBx5CWRb/pwEVxDxHFaru
=1kAq
-----END PGP SIGNATURE-----