[Twisted-web] how are solving the calls to the children in nevow?

Matt Goodall matt at pollenation.net
Thu Jul 7 17:47:35 MDT 2005

Alberto Trujillo wrote:

> Hello:
> I have been following this example
> "http://nevowexamples.adytum.us/childrenhtml/"to know how works the
> calls to the children with nevow, but still it's not enough clear for me.
> I even add a new child in the childFactory and some print command to
> follow the way of the calls. Here I show you my modifications:
>    def childFactory(self, ctx, name):
>        print "NAME = " + name
>        if name in ['1', '2', '3']:
>            return ChildPage(name)
>        elif name == 'one':
>            return OneRoot()
>    def locateChild(self, ctx, segments):
>        child, remainingSegments = rend.Page.locateChild(self, ctx,
> segments)
>        print "CHILD = " + str(child) + " SEGMENT = " +
> str(remainingSegments)
>        if child:
>            print "IN THE IF"
>            return child, remainingSegments
>        return ChildPage('/'.join(segments)), []
> My question is why each time that I call to "one" it goes inside
> "locateChild" wheter "one" is place in "childFactory", here is a trace
> of my server.

Only locateChild(self, context, segments) is part of the IResource API.
All the child_ and childFactory support is provided by the
rend.ChildLookupMixin class that rend.Page subclasses.

What's happening in the above code is that you have an overridden
locateChild method that calls rend.Page.locateChild.
rend.Page.locateChild does the child_ and childFactory magic and calls
your childFactory method. Your childFactory prints the NAME and returns
the child resource back to your locateChild method which then also
prints it out as CHILD.

> 2005/07/07 13:52 IST [HTTPChannel,0,] NAME = one
> 2005/07/07 13:52 IST [HTTPChannel,0,] CHILD = <one.OneRoot
> object at 0x40701eac> SEGMENT = ()
> 2005/07/07 13:52 IST [HTTPChannel,0,] IN THE IF
> 2005/07/07 13:52 IST [HTTPChannel,0,] - -
> [07/Jul/2005:12:52:11 +0000] "GET /one?id=1 HTTP/1.1" 200 47
> "http://localhost:8080/" "Mozilla/5.0 (X11; U; Linux i686; en-US;
> rv:1.7.8) Gecko/20050517 Firefox/1.0.4 (Debian package 1.0.4-2)"
> 2005/07/07 13:52 IST [HTTPChannel,0,] NAME = favicon.ico
> 2005/07/07 13:52 IST [HTTPChannel,0,] CHILD = None SEGMENT = ()
> 2005/07/07 13:52 IST [HTTPChannel,0,] - -
> [07/Jul/2005:12:52:11 +0000] "GET /favicon.ico HTTP/1.1" 200 684 "-"
> "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050517
> Firefox/1.0.4 (Debian package 1.0.4-2)
> And when I return to the father, who call to childrenRoot class again,
> and what is favicon.ico?. I show you the results here.
> 2005/07/07 13:58 IST [HTTPChannel,1,] NAME = favicon.ico
> 2005/07/07 13:58 IST [HTTPChannel,1,] CHILD = None SEGMENT = ()
> 2005/07/07 13:58 IST [HTTPChannel,1,] - -
> [07/Jul/2005:12:58:34 +0000] "GET /favicon.ico HTTP/1.1" 200 684 "-"
> "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050517
> Firefox/1.0.4 (Debian package 1.0.4-2)"

favicon.ico is something the browsers request. It's the annoying little
icon browsers add to tabs and bookmarks. I hate it. See

> I would like to know as well if I must to implement all these methods
> each time that I'm working with children, and what is segments.

segments is simply a tuple of the remaining URI path segments.

A URL of http://localhost/foo/bar has segments ('foo', 'bar'). Nevow
tries to turn those segments into child resources until there are no
more segments left. A typical sequence of events for that URL might be:

1. Nevow asks the root resource to turn 'foo' into a resource. The root
resource returns a foo resource.
2. Nevow asks the foo resource to turn 'bar' into a resource. The foo
resource returns a bar resource.
3. Nevow seems that there are all segments have been used and asks the
bar resource to render itself.

However, as you will see below the root resource could consume both
'foo' and 'bar' and return a bar resource directly.

How you choose to traverse the URI depends on what you know and need to
do ...

If you know the name of a child resource at development time and the
child resource never changes then use a child_ class attribute:

    class Page(rend.Page):
        child_css = static.File('/path/to/css')

If you know the name of a child but you need to create it in a special
way use a child_ method:

    class Page(rend.Page):
        def child_time(self, ctx):
            return TimePage(time.now())

If you don't know the name of the resource, i.e. it's a database id or
something similar, then use childFactory:

    class Page(rend.Page):
        def childFactory(self, ctx, name):
            obj = db.getObj(int(name))
            return ChildPage(obj)

Finally, if you want absolute control, i.e. to consume two URI segments
in one go, then override locateChild:

    class Page(rend.Page):
       def locateChild(self, ctx, segments):
          if segments[:2] == ('foo', 'bar'):
             return BarPage(), segments[2:]
          return rend.Page(self, ctx, segments)

Note how that example compares the first 2 segments and consumes both
'foo' and 'bar' by returning a new BarPage child and the remaining
segments - segments[2:]. Only locateChild is able to process more than
one segment at a time.

Personally, I nearly always use child_ and childFactory. I only using
locateChild for more comlpex URL traversal problems.

> Sorry I know that are a lot of question, but I don't have access to
> the IRC channel and I couldn't understand the information in
> "inevow.IReource". 

Hope this explains it well enough now.

Cheers, Matt

    /  \__     Matt Goodall, Pollenation Internet Ltd
    \__/  \    w: http://www.pollenation.net
  __/  \__/    e: matt at pollenation.net
 /  \__/  \    t: +44 (0)113 2252500
 \__/  \__/
 /  \	       Any views expressed are my own and do not necessarily
 \__/          reflect the views of my employer.

More information about the Twisted-web mailing list