[Twisted-web] nested nevow:data?

Jeff Bowden jlb at houseofdistraction.com
Mon Aug 2 16:52:31 MDT 2004

Donovan Preston wrote:

> On Aug 2, 2004, at 1:36 PM, Jeff Bowden wrote:
>> Should it be possible to nest nevow:data declarations in a template?  
>> E.g.
>>    <html nevow:data="order" nevow:render="order">
>>    <head><title>Order <nevow:slot name="order_number"/></title></head>
>>    <body>
>>      <h1>Order <nevow:slot name="order_number"/></h1>
>>      <ul nevow:data="order_items" nevow:render="sequence">
>>        <li nevow:pattern="item" nevow:render="mapping">
>>           ... slots and stuff
>>        </li>
>>       </ul>
>>    </body>
>> When I do this I get a big long stack trace rooted in 
>> nevow/accessors.py.  It works fine if I remove the outer 
>> nevow:data="order" (and dummy up a static fillSlots call for 
>> "order_number" in render_order).  It also works if I remove the inner 
>> section.
>> I can work around the problem by putting the nevow:data="order" 
>> declaration  in multiple places but it would be handy if I didn't 
>> have to.  Is this a bug or is it by design?
> What type is "order"? A data directive puts that data on the context 
> stack for the duration of that xml node; additional data directives 
> are handled by getting an IContainer adapter around the nearest data 
> on the stack. If, as I am suspecting, "order" is a rich python class, 
> what you want to do is either mix in DataFactory to your order class 
> and declare that it implements IContainer, or provide an IContainer 
> adapter for your order class (which is probably a subclass of 
> DataFactory). For example:
> class OrderContainer(DataFactory):
>     def data_order_number(self, ctx, data):
>         return self.original.orderNumber
>     def data_order_items(self, ctx, data):
>         return self.original.items
> compy.registerAdapter(OrderContainer, MyOrderClass, IContainer)
> This is by design. It's intended to work in such a way that fragments 
> of template can have data pushed at them, and they can operate without 
> knowledge of the context of the entire page.
> The biggest mistake people make in this area is when they do something 
> like push a list onto the context and then try to access another data_ 
> method of the Page class. The directive will be satisfied by doing 
> IContainer(theList).child(theDirective), and since the IContainer 
> adapter for lists doesn't know how to handle anything except integer 
> indexes, they get an exception.
> eg:
> <ol n:data="someList" n:render="sequence">
>     <li n:pattern="header" n:data="someOtherDirective">
>     <!-- This won't work because "someList" is the topmost data on the 
> stack, and thus we will get an exception instead of having our 
> data_someOtherDirective method called on our Page -->
>         Header here
>     </li>
>     <li n:pattern="item" n:render="string">
>         Items here
>     </li>
> </ol>

So you are saying is that a nested data directive will try to reference 
the outer data directive rather than the page class?  Wow, I'm glad I 
asked.  I wouldn't have guessed that based on the tutorial.

Is there a high-level overview or diagram somewhere of how all pieces of 
Nevow fit together?

OK anyway so yeah, as you guessed, "order" is a python list and the 
exception I get matches your description exactly.  The 
OrderContainer(DataFactory) suggestion seems like a conceptually clean 
solution for my current task but it won't be quite so tidy when I go to 
nest *it* inside of a more-or-less unrelated outer directive, which is 
my next step.  Maybe I'll make a data container that just passes through 
requests to the page and wraps them in a new instance of itself before 
returning them (i.e. simple nesting with no implied relationship between 
inner and outer scopes).

More information about the Twisted-web mailing list