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).