[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