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

Reply via email to