Ricky Iacovou wrote:
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?
I suspect it's because when SecondPage sees the request was POST'ed and
assumes it's a form POST. Processing the POST will re-find the
FirstPage's form and processes it again which returns a SecondPage, etc.
I'm not sure if that's a bug or a feature/limitation ;-).
Even if SecondPage was rendered correctly after submitting FirstPage, I
think Formal would have a hard time finding SecondPage's form because
the URL would resolve to a FirstPage resource.
Interesting.
I'll add a ticket and have a think about it.
The way I've done this sort of thing is to make FirstPage HTTP redirect
to another URL to display SecondPage, passing data from FirstPage to
SecondPage using request args. (Hint: return a nevow.url.URL instance
from FirstPage's form's submit method.)
If there's a lot of data to pass around you might need to resort to
sessions. Yucky but, hey, it's the web.
It would certainly be nicer to chain form pages together.
Hope this helps, even if it doesn't solve your problem.
- Matt
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
--
_______________________________________________
Twisted-web mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
--
__
/ \__ Matt Goodall, Pollenation Internet Ltd
\__/ \ w: http://www.pollenation.net
__/ \__/ e: [EMAIL PROTECTED]
/ \__/ \ t: +44 (0)113 2252500
\__/ \__/
/ \ Any views expressed are my own and do not necessarily
\__/ reflect the views of my employer.
_______________________________________________
Twisted-web mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web