[Twisted-web] Cascading forms in formal (example code included)
Ricky Iacovou
iacovou at gmail.com
Wed Jun 14 08:34:12 CDT 2006
Hi there.
I've been wrestling with a Nevow/formal problem for a day now (though it might
not be formal-specific); I'm hoping someone with more Nevow experience might
be able to shed some light on the problem.
I've reduced the problem to the Python code below; run it with 'twistd -noy
file.py' and point your browser to localhost:8080.
The first page is a form; anything you enter gets handled by
FirstPage.handler(). I want to have this form lead to another form which asks
for further information based on the input to the first form.
If you enter the string 'test' in the first page, you will go through an
intermediate static page. Anything else will take you directly to another
form.
Tv on #twisted.web pointed out that I can return an IResource from a form
handler. I'm trying to do this here: I create a SecondPage() object and
return that, but the server goes into an infinite loop, constantly handling
the first page results (printing, "User string was: " ...).
[In my actual code, I can Ctrl-C the server at this point; in this example
code, I actually have to Ctrl-Z and kill -9 the server. I don't know why.]
Note that using the static intermediate page (i.e. simply return a TestPage()
object from FirstPage.handler()) works peachily. In fact, when you access a
SecondPage instance as a child of the FirstPage (there's a link on the static
page), it also works.
Does anyone have any idea why returning the second form page directly creates
an infinite loop?
Thanks,
Ricky
--
Code starts here
--
from twisted.python import util
from twisted.internet import defer
from twisted.application import strports
from twisted.application import service
from nevow import appserver
from nevow import rend
from nevow import loaders
from nevow import tags as T
from nevow import url
import formal
class SecondPage ( formal.ResourceMixin, rend.Page ):
def form_example ( self, ctx ):
form = formal.Form()
form.addField ( 'description',
formal.String(),
label = "Type Stuff",
description = "For example, 'marmalade'"
)
form.addAction ( self.handler, label = "Go" )
return form
def handler ( self, ctx, form, data ):
print "Form data was: ", data
# End of form chain; just return a static page.
return TestPage()
docFactory = loaders.stan (
T.html [ T.head [ T.title [ "Second Page" ] ],
T.body [ T.directive ( 'form example' ) ] ] )
class FirstPage ( formal.ResourceMixin, rend.Page ):
def form_example ( self, ctx ):
form = formal.Form()
form.addField ( 'user_string',
formal.String(),
label = "Type Stuff",
description = "Type 'test' to go to TestPage."
)
form.addAction ( self.handler, label = "Go" )
return form
def handler ( self, ctx, form, data ):
user_string = data [ 'user_string' ]
print "User string was: ", user_string
if str ( user_string ) == 'test':
# This works:
page = TestPage()
else:
# ... but this doesn't:
page = SecondPage()
# Also, how to pass in the 'state' (i.e. user_string)? Should we pass
# it as a construction argument of the Page?
# In the Real Code we make a call to an XML-RPC server in the handler,
# which is why we return a deferred here rather than the page itself.
return defer.succeed ( page )
# Instantiate a SecondPage so it can be accessed indirectly.
child_secondPage = SecondPage()
docFactory = loaders.stan (
T.html [ T.head [ T.title [ "First Page" ] ],
T.body [ T.directive ( 'form example' ) ] ] )
class TestPage ( rend.Page ):
docFactory = loaders.stan (
T.html [ T.head [ T.title [ "Test Page" ] ],
T.body [ "Visit the ",
T.a ( href = '/secondPage' ) [ "Second Page" ] ] ] )
application = service.Application ( 'Broken Forms' )
site = appserver.NevowSite ( resource = FirstPage() )
server = strports.service ( "8080", site )
server.setServiceParent ( application )
--
Code ends here
--
More information about the Twisted-web
mailing list