Am Donnerstag, den 19.05.2005, 11:56 -0400 schrieb Ken Winter:
-----Original Message----- From: Lennart Regebro [mailto:regebro@gmail.com] Sent: Thursday, May 19, 2005 11:07 AM To: ken@sunward.org Cc: J Cameron Cooper; zope@zope.org Subject: Re: [Zope] How to make a ZPT-based form that calls itself? (Part II)
On 5/19/05, Ken Winter <ken@sunward.org> wrote:
* I assume you include data retrieved from (and updated in) an underlying relational database.
* Does "data" also include parameters (or arguments, or query string variables, or whatever you call them) passed from one HTML page to the next?
Sure.
This parameter-passing is what I seem to be having trouble with. How does that script get the info it needs from the previous page? In my example, when my "personform.htm" updates a record and then re-calls itself, how does it get the person_id identifying the record it's supposed to display the second time around?
You put it in a hidden input-field.
That's what I've been doing (I think), and it's not working. Let me paste in a listing of the whole <div> tag that I'm using (with some irrelevant bits clipped out):
<div tal:repeat="person python:here.dbobs.read_person_by_id_py(context.REQUEST.person_id)">
the read_person_by_id_py can probably read the request variable by its own. So no need to pass it like that.
<table height="fit" width="fit" border="0" align="left" cellpadding="0" cellspacing="0"> <tr height="fit"> ... <td width="fit" align="left"> <em><strong> <font size="+2"><p align="left" tal:content="string:
Ugh! Make yourself familar with moden HTML and CSS, this saves a lot of typing - and makes smaller templates.
${person/first_name} ${person/middle_names} ${person/last_name}">Name Filler</p></font> </strong></em></td> </tr> </table><br> <p> </p><br> <form name="form1" id="form1" method="post" action="dbobs/update_person_py"> <table width="fit" border="0" cellspacing="0" cellpadding="0"> <tr height="fit"> <td width="fit" align="right"><em> First Name: </em></td> <td width="fit"><input type="text" name="first_name" value="" tal:attributes="value string:${person/first_name}"/></td>
value person/first_name would be ok.
</tr> <tr height="fit"> <td width="fit" align="right"><em> Middle Name(s): </em></td> <td width="fit"><input type="text" name="middle_names" value="" tal:attributes="value string:${person/middle_names}"/></td> </tr> <tr height="fit"> <td width="fit" align="right"><em> Last Name: </em></td> <td width="fit"><input type="text" name="last_name" value="" tal:attributes="value string:${person/last_name}"/></td> </tr> </table> <input type="hidden" name="person_id" value="" tal:attributes="value string:${person/person_id}"/> <p> <input type="submit" name="Submit" value="Save Changes" /> <input type="reset" name="Reset" value="Cancel Changes" /> </p> </form> </div>
The tal:repeat in the first line is my attempt to grab all my data at the start. The hidden input field at the bottom is my attempt to pass the person_id along when the page is trying to re-call itself. The whole thing works OK when the page is called from elsewhere, passing the person_id in the form of a URL argument string along these lines: "personform.htm?person_id=35". But it doesn't work when the Python script " update_person_py()" called by "personform.htm" itself tries to re-call "personform.htm", trusting the hidden field to convey the person_id data. Instead, the data update is performed but the next thing the browser shows is an AttributeError=person_id. The body of the "update_person_py" script is:
id = context.REQUEST.get('person_id') if id: container.update_person(\ person_id=id,\ first_name=context.REQUEST.get('first_name'),\ middle_names=context.REQUEST.get('middle_names'),\ last_name=context.REQUEST.get('last_name')) context.REQUEST.RESPONSE.redirect('personform.htm')
the redirect above when the script is included like you shown, causes the header: location: to be set. Then Zope outputs all the HTML from ZPT and the browser reads the location: header and makes a new request with the URL found there. This new request obviously misses all the form information.
What's wrong with this picture?
I'd use the controller-script approach here. This is, you have the python script, which checks the REQUEST for form information and perhaps initialize some variables with default data. value=context.REQUEST.get('value',default) is the pattern here. You would check for the name of the submit button or some essential form data. Depending on action, do your updates in database or whatever. Next read data out of database. Usually you connect this to a preparation of data for the template. The pattern is like this: somedata=[{'value1':r.value1, # use comments a lot 'value2':r.value2, # possibly in every 'value3':r.value3+r.value4 # line } for r in context.your_zsqlmethod(arg1=argument1)] You can do a lot of preparation here. next you decide which template you want to output (can depend on request state or you use the same template for all states) return context.yourtemplate(data=somedata,value=value) Where you use tal:repeat="row options/data" and tal:content="options/value" So you can just use path expressions all over the place since you prepare all the data in your script. Complex data structures can be passed in (nested) dictionaries. HTH Tino Wildenhain