[Twisted-Python] again on nested sequence
Valentino Volonghi aka Dialtone
dialtone at divmod.com
Sun Jul 16 18:23:30 EDT 2006
On Sun, 16 Jul 2006 16:18:07 -0200, Manlio Perillo <manlio_perillo at libero.it> wrote:
This is off topic here... Twisted-web is the list. Anyway:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:n="http://nevow.com/ns/nevow/0.1"
lang="it" xml:lang="it">
<head>
<title>Nested sequence</title>
</head>
<body>
<ul n:render="sequence" n:data="control_list">
# Here you call data_control_list.
# The result of data_control_list becomes the IContainer implementor
# from now on inside this <ul> tag.
<li n:pattern="item" n:render="control">
# You call the render_control method on the IRenderer implementor which
# is the Main instance this method fills 2 slots ctrl_label and ctrl_name.
# every slot inside this <li> tag that has one of those 2 names will be
# filled unless an inner tag fills one of those slots with a different
# value
<label><n:slot name="ctrl_label"/>
<select n:render="sequence" n:data="option_list">
# Here you call IContainer(ctx).child('option_list')
# IContainer(ctx) is what was returned at the beginning with
# data_control_list.
# That result of that call is a list and the IContainer adapter
# for lists does position lookup.
# __getitem__ for lists takes integers and since all the values
# coming from the template are strings they have to be converted
# to integers. The value coming is 'option_list' and this cannot
# be converted to an integer. And thus the error.
# The solution? Fairly simple, although it would have been better that,
# after I explained how part of the rendering works, YOU tried to find
# the solution, anyway I'll explain it :).
#
# There are 2 solutions (actually more but only 2 that keep using templates):
# - Return a list of dictionaries from control_list
# - Return a list of 3-tuples from control_list
# To avoid changing the template too much let's just see how the
# previous line should have been for the second option:
# <select n:render="sequence" n:data="2">
# That'it.
# def data_control_list(self, ctx, data):
# return [('a', 'first', ('1', 'uno')), ('b', 'second', ('2', 'due'))]
# Of course I hate this solution because it involes too much code...
# you already wrote 3 methods where one would have been largerly enough.
<n:attr name="name"><n:slot name="ctrl_name" /></n:attr>
<option n:pattern="item" n:render="option">
<n:attr name="label"><n:slot name="opt_label" /></n:attr>
<n:attr name="value"><n:slot name="opt_value" /></n:attr>
</option>
</select>
</label>
</li>
</ul>
</body>
</html>
The best solution is the following (NOT TESTED, but should work):
class Main(rend.Page):
docFactory = loaders.xmlfile('nested.xhtml')
def data_control_list(self, ctx, data):
return [{'ctrl_name': 'a',
'ctrl_label': 'first',
'option_list': {'opt_value': '1',
'opt_label': 'uno'}
},
{'ctrl_name': 'b',
'ctrl_label': 'second',
'option_list': {'opt_value': '2',
'opt_label': 'second'}
}]
# nested.xhtml
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:n="http://nevow.com/ns/nevow/0.1"
lang="it" xml:lang="it">
<head>
<title>Nested sequence</title>
</head>
<body>
<ul n:render="sequence" n:data="control_list">
<li n:pattern="item" n:render="mapping">
<label><n:slot name="ctrl_label"/>
<select>
<n:attr name="name"><n:slot name="ctrl_name" /></n:attr>
<nevow:invisible n:render="sequence" n:data="option_list">
# Yes, I added the tag above because I'm unsure about the way
# n:attr is dealt with when it is between the sequence render and
# the patterns inside the sequence. This solution removes the
# uncertainty. It's generally better to keep the slots filled
# directly inside the interested renderer without crossing any other
# special renderer tag like this template was doing.
<option n:pattern="item" n:render="mapping">
<n:attr name="label"><n:slot name="opt_label" /></n:attr>
<n:attr name="value"><n:slot name="opt_value" /></n:attr>
</option>
</nevow:invisible>
</select>
</label>
</li>
</ul>
</body>
</html>
As you can see this solution involves a considerably simpler and more generic
Page object that can be reused for a variety of usecases (especially when the
data_* method simply runs a query instead of returning an hardcoded result,
if the query returns a list of dictionaries already simply putting the query as
a Page parameter you'll be able to reuse the whole Page code except the query
and then simply change the templates as needed.
More information about the Twisted-Python
mailing list