[Grok-dev] grok and urls
faassen at infrae.com
Mon Oct 30 10:05:25 EST 2006
So here I'm replying to myself, investigating some ways to make URL
Martijn Faassen wrote:
> Meanwhile, grok also needs to generate various kinds of URLs. the
> grokwiki has a number of places where URLs are involved:
> * the redirect in wiki.py does self.request.response.redirect('home')
> That's a relative URL that just happens to work. Relative URLs
> unfortunately don't always happen to work.
Perhaps we need to have a method on the view that helps redirecting, as
we do it often:
this saves us typing the whole '.request.response' bit.
> * in page.Index there's a before method which does:
> zapi.absoluteURL(self.context.__parent__, self.request)
> to get the URL to the wiki itself.
It's interesting to note here that we generate a URL to__parent__. I
suspect this shows up in many applications. Another thing grokwiki
doesn't do yet but will appear in other applications is to generate a
URL to the site:
A simple method on grok.View might help again:
perhaps automated as:
though this encourages URL construction in Page Templates, something we
may perhaps want to discourage, leading people to a good API..
we may also be interested in:
I realize by the way that I'm adding all kinds of utility methods to the
grok.View class here. While we run the risk of name clashes, I think
it's worth it. Suddenly there's no need to pull up self.request all the
time anymore and an import goes away.
> * in page.Edit there's another interesting
I'll insert some information here that I forgot in my last mail:
self.wiki = self.context.__parent__
This is done for reuse later. It's not actually used by anything else
but the code below that I can find, so there doesn't look like a good
reason this is an assignment on the view instead of just a local variable.
> wiki_url = zapi.absoluteURL(self.wiki, self.request)
> self.request.response.redirect("%s/%s" % (wiki_url,
> This one is particularly horrible as it takes place in a 'before()'
> method. We have a special class of URL redirects which happen
> after form submits and we're sort of misusing before() here to make
> that happen.
I won't think here about making this be outside before(). This is a
topic for later - the whole view/form redirection issue (we often want
to carry status messages along too).
In the new spelling this could look like:
> * then in page_templates/edit.pt, there's a form submit to request/URL
> We get the URL from the request here.
perhaps this can become:
which then calls url() without arguments which will deliver the URL for
the view itself. Then again, URL generation in page templates does open
a whole separate can of worms..
> * and in page_templates/index.pt there's a tal:attributes="href
> We use the absolute_url view that gets registered for lots of things,
> looking it up by name. Then we tack /edit after it.
This one is interesting, as it generates a URL to a 'sibling view' on
the current context object. I expect this is something that happens
quite frequently, so we need a construct for it. In code, it might look
or as I explain later, we could overload the behavior of 'url' a little:
Unfortunately in a page template we're interested in avoiding Python
expressions like this:
though it isn't too bad compared to the original construct...
Later on I discuss some possible more magical options, but they don't
satisfy me yet, really.
> * and then in layout.pt
> tal:define="wiki context/__parent__;
> wiki_url wiki/@@absolute_url"
> and later
> <a tal:attributes="href string:$wiki_url/$page"
> And here we tack do some more construction, this time constructing
> the name from two other names.
The first define would be easy:
of course this is only done to do URL construction in a page template. I
think we should see whether we can avoid having to do such a lot in grok.
sibling_url (or .url('sibling') doesn't work, as we're not pointing to
siblings of the view here, but siblings of the context. Perhaps this
gives us a clue about sibling_url being misnamed...
Above we construct a URL to the object by knowing about the structure of
the site. We can do this in a different way though; we already have the
page object so there's no reason to know about the structure of the site
to construct a link to it:
This links to the index view of page. If we want to construct a url to a
view on the page, we might do this:
But that leads to more Python in a page template. There's another, more
severe problem: both examples also imply that grok.Model supports a
url() method, and this may be something harder to defend than adding
methods to views - the notion that our content base class is very simple
is one I'd like to keep.
Above we define view.url() as optionally getting an object, so that'd
help us here:
what if we want to construct URLs to edit pages, though?
tal:attributes="href python:view.url(page, 'edit')"
again, somewhat ugly from page templates though as we use Python
expressions... *Not* uglier than what we replaced, though!
Let's try to sketch out a minimal API:
"""Redirect to given URL"""
def url(obj=None, view=''):
If no arguments given, construct URL to view itself.
If only obj argument is given, construct URL to obj.
If only view is given (or string as first argument, a bit of
magic there), construct view URL to view with that name on our
If both object and view arguments are supplied, construct
view URL to view on that object.
>>> view.url(view.context, 'display')
>>> parent = view.context.__parent__
>>> view.url(parent, 'display')
this is the minimal thing I can think of that helps us in Python code.
In page templates it's going to be trickier, if we want to avoid python
Could we make pass in a magic 'url', along the lines of 'static', that
helps us here?
>>> zpt('<a tal:attributes="href url">Link</a>')
>>> zpt('<a tal:attributes="href url/display">Link</a>')
So far so good, but it breaks down when we want to link to objects:
>>> zpt('<a tal:attributes="href url/view/context">') # XXX makes no
More information about the Grok-dev