Validation in Custom Form using crud

97 views
Skip to first unread message

Gary

unread,
May 2, 2009, 1:37:40 PM5/2/09
to web2py Web Framework
The following MVC is used to create/update/read a single table. The
validation for not empty works with the {{=form}} but not the custom
HTML. Both versions are displayed in the same form and the data is
changed and validated via either submit button, but the error message
is only displayed in the top, standard form.

Can anyone see what is causing the different behavior?

Thanks

Model
-------
try:
from gluon.contrib.gql import * # if running on Google App Engine
except:
db = SQLDB('sqlite://storage.db') # if not, use SQLite or other
DB
else:
db = GQLDB() # connect to Google BigTable
session.connect(request, response, db=db) # and store sessions
there
##
db.define_table('testtable',SQLField('testfield1','string'),SQLField
('testfield2','string'))
db.testtable.testfield1.requires=IS_NOT_EMPTY()

from gluon.tools import Mail, Auth, Crud # new in web2py 1.56
crud=Crud(globals(),db) # for CRUD helpers using
auth
crud.settings.update_next = URL(r=request, f='index')

Controller
------------
def index():
session.action = "update"
redirect(URL(r=request,f='testdata',args=["3"]))

def testdata():
if request.vars.submit1: session.action = "create"
if request.vars.submit2: session.action = "update"
if request.vars.submit3: session.action = ""
if session.action == "create":
return dict(form=crud.create(db.testtable))
elif session.action == "update":
id=request.args[0]
return dict(form=crud.update(db.testtable,id))
else:
id=request.args[0]
return dict(form=crud.read(db.testtable,id))

def data():
response.view="%s/%s/%s.html" %
(request.controller,request.function, request.args[0])
return dict(form=crud())

View (default/testdata)
-----------------------------
{{extend 'layout.html'}}
<h1>Testdata
{{if session.action == "update":}}
Update
{{elif session.action == "create":}}
Add
{{pass}}
</h1>
{{=form}}
=========================================
<form action="" enctype="multipart/form-data" method="post">
<table>
<tr id="testtable_testfield1__row">
<td><label for="testtable_testfield1"
id="testtable_testfield1__label">Testfield1: </label></td>
{{if session.action == "update":}}
<td><input class="string" id="testtable_testfield1"
name="testfield1" type="text" value="{{=form.record.testfield1}}" /></
td>
{{elif session.action == "create":}}
<td><input class="string" id="testtable_testfield1"
name="testfield1" type="text" value="" /></td>
{{else:}}
<td>{{=form.record.testfield1}}</td>
{{pass}}
<td></td>
</tr>
<tr>
<td><label >Testfield2:</label></td>
{{if session.action == "update":}}
<td><input class="string" name="testfield2" type="text"
value="{{=form.record.testfield2}}" /></td>
{{elif session.action == "create":}}
<td><input class="string" id="testtable_testfield1"
name="testfield2" type="text" value="" /></td>
{{else:}}
<td>{{=form.record.testfield2}}</td>
{{pass}}
<td></td>
</tr>
{{if session.action == "update":}}
<tr id="delete_record__row">
<td><label for="delete_record" id="delete_record__label">Check to
delete:</label></td>
<td><input class="delete" id="delete_record"
name="delete_this_record" type="checkbox" value="on" /></td>
<td></td>
</tr>
{{pass}}
</table>
{{include 'buttons.html'}}
</form>

dlypka

unread,
May 2, 2009, 5:21:07 PM5/2/09
to web2py Web Framework
Look like there are some typos:

typo #1 (perhaps?):
<form action="" enctype="multipart/form-data" method="post">
<table>
<tr id="testtable_testfield1__row">
<td><label for="testtable_testfield1" <---- what is attribute
'for' in 'for=="testtable_testfield1"??? Should it be 'form', not
'for"?
<--- and
even if 'form' is intended, that does not seem a typical attribute for
a <label> tag...


typo #2:
<td><input class="string" name="testfield2" type="text" <--- it
is missing id="testtable_testfield2"
value="{{=form.record.testfield2}}" /></td>

typo #3:
{{elif session.action == "create":}}
<td><input class="string" id="testtable_testfield1" <------- I
think it should be id="testtable_testfield2"
name="testfield2" type="text" value="" /></td>


I also suggest that you simply do a View Source in the browser and
carefully read over the generated markup to look for problems.

Gary

unread,
May 2, 2009, 7:37:12 PM5/2/09
to web2py Web Framework
Thank you for your reply. There was a typo #3, but the 'for' in #1
is a valid label option. Actually, I copied the basic <input> and
<label> statements from the {{=form}}, but I eliminated the
information in #2 when was playing with the various options to see how
they effected the display. I guess I introduced the typo during the
manipulation.

I never saw the 'for' option before, but found an explanation at
http://www.w3schools.com/tags/tag_label.asp. FYI, it "Specifies which
form element a label is bound to".

Unfortunately, even after I checked and corrected all the syntax, I
still have the same issue with the display. If you have any other
ideas I would greatly appreciate them.

Thanks and regards,
Gary

mdipierro

unread,
May 2, 2009, 9:53:47 PM5/2/09
to web2py Web Framework
Because of the typos. Can you post the code again and re-state the
problem?

Massimo

On May 2, 6:37 pm, Gary <gary.k.ma...@gmail.com> wrote:
> Thank you for your reply.   There was a typo #3, but the 'for' in #1
> is a valid label option.  Actually, I copied the basic <input> and
> <label> statements from the {{=form}}, but I eliminated the
> information in #2 when was playing with the various options to see how
> they effected the display.  I guess I introduced the typo during the
> manipulation.
>
> I never saw the 'for' option before, but found an explanation athttp://www.w3schools.com/tags/tag_label.asp.  FYI, it "Specifies which

John Heenan

unread,
May 2, 2009, 8:54:50 PM5/2/09
to web2py Web Framework
Hi Gary

You have got an interesting approach. However I think it is more
complicated than necessary for what you want to achieve.

Since your goal appears to be to customise crud layouts then why not
just stick to that instead of also bypassing crud in the testdata
controller action? You cannot get the error message you want because
your testdata action does not do anyting that will initiate a
validator action (such as the normal 'if form.accepts
(request.vars,session):'. To get normal crud validation action make
sure your form uses your data controller action.

Also in your custom form you are using a method to extract the read or
update values from a SQLFORM generated form in an undocumented way
(form.record.field_name). If it worked once with web2py it does not
work now. The documented way can be found in
http://www.web2py.com/AlterEgo/default/show/205
such as form.custom.inpval.field_name.

To use crud in a simple manner you will need to include
<input value="{{=form.formkey}}" type="hidden" name="_formkey" />
<input value="{{=form.formname}}" type="hidden" name="_formname" />

as well as mame the form action="data" as in
<form action="data" enctype="multipart/form-data" method="post">

Also you will need to make sure all the required templates exist or in
the controller data add some tests around
response.view="%s/%s/%s.html" %
(request.controller,request.function, request.args[0])
to only use the templates you want

Regards

John Heenan

dlypka

unread,
May 2, 2009, 10:10:56 PM5/2/09
to web2py Web Framework
I suggest just doing a File .. View Source in your browser and study
it carefully and look
for a difference between the Auto Crud code and the hand crafted code
areas of the generated Source
as far as the validation is concerned.

On May 2, 7:37 pm, Gary <gary.k.ma...@gmail.com> wrote:
> Thank you for your reply.   There was a typo #3, but the 'for' in #1
> is a valid label option.  Actually, I copied the basic <input> and
> <label> statements from the {{=form}}, but I eliminated the
> information in #2 when was playing with the various options to see how
> they effected the display.  I guess I introduced the typo during the
> manipulation.
>
> I never saw the 'for' option before, but found an explanation athttp://www.w3schools.com/tags/tag_label.asp.  FYI, it "Specifies which
> > > </form>- Hide quoted text -
>
> - Show quoted text -

John Heenan

unread,
May 2, 2009, 10:55:40 PM5/2/09
to web2py Web Framework
The correct form action for customised crud templates is not simply
<form action="data" enctype="multipart/form-data" method="post">
as I stated in my previous post

The correct action for a create form for example can be found by
taking away '_create' from form.formname. For example
<form action="data/create/{{=form.formname.split('_')[0]}}"
enctype="multipart/form-data" method="post">

You can look at examples or the source code to get the appropriate
action names and so form name manipulations for form actions.


John Heenan



On May 3, 10:54 am, John Heenan <johnmhee...@gmail.com> wrote:
> Hi Gary
>
> You have got an interesting approach. However I think it is more
> complicated than necessary for what you want to achieve.
>
> Since your goal appears to be to customise crud layouts then why not
> just stick to that instead of also bypassing crud in the testdata
> controller action? You cannot get the error message you want because
> your testdata action does not do anyting that will initiate a
> validator action (such as the normal 'if form.accepts
> (request.vars,session):'. To get normal crud validation action make
> sure your form uses your data controller action.
>
> Also in your custom form you are using a method to extract the read or
> update values from a SQLFORM generated form in an undocumented way
> (form.record.field_name). If it worked once with web2py it does not
> work now. The documented way can be found inhttp://www.web2py.com/AlterEgo/default/show/205

Álvaro Justen [Turicas]

unread,
May 3, 2009, 3:19:56 AM5/3/09
to web...@googlegroups.com
I think this is not really what you want, but could help: you can
validate data (using validators) if you use helpers to create your
forms. Creating forms with helpers is more flexible than with Crud.
Try something like this:

def test():
f = FORM('Is web2py cool? Why?',
SELECT(OPTION('Yes', _value='y'), OPTION('No',
_value='n'), _name='opts', requires=IS_IN_SET(['y'],
error_message='Errr...wrong answer')),
INPUT(_type='text', _name='why', _value="'cause python
rules", requires=IS_NOT_EMPTY()),
INPUT(_type='submit', _name='btnSubmit', _value='ok'))
if f.accepts(request.vars):
response.flash = 'form accepted'
elif request.vars.btnSubmit:
response.flash = 'error in form'
return dict(myform=f, v=request.vars)

You can create the layout in HTML and elements in controller (INPUT,
SELECT etc.) and then put them in HTML with {{=varname}}.
--
Álvaro Justen
Peta5 - Telecomunicações e Software Livre
21 3021-6001 / 9898-0141
http://www.peta5.com.br/

Gary

unread,
May 3, 2009, 2:51:59 PM5/3/09
to web2py Web Framework
Thanks to all for your input and suggestions. I've tried to make the
changes without effecting the functionality or the goal of using the
'crud' controllers.

Massimo - I'll repost the application with the changes below.

Alvaro - I've considered abandoning the use of the crud controllers
and use 'form', but I've gone this far and it has become a challenge,
plus I hope to add to the knowledge base about the use of the crud
code.

dlypka - I've taken your suggestion and (essentially) copied the code
from the {{=form}} to be as sure as I could to duplicate the layout

John - I've incorporated the form.custom.inpval. When I looked at
what was generated by {{=form}} it didn't seem to need the form
action. I may be missing something, but everything works except the
response.error display, so I'm a little confused. Massimo has asked
to see the updated version of the code, so I'll let him take a look
before I add too much more.

Here is the MVC. The view contains both custom code and {{=form}}.
It doesn't make any difference which input fields or submit button is
used, the data is handled properly. The problem is, if you leave
'testfield1' blank, only the {{=form}} version displays the 'cannot be
empty' message. The error is not displayed in the custom form. The
code for the labels and fields are copied directly from the {{=form}}
source of the page and modified to display the
form.custom.inpval.fieldname variables.

Model
--------
try:
from gluon.contrib.gql import * # if running on Google App Engine
except:
db = SQLDB('sqlite://storage.db') # if not, use SQLite or other
DB
else:
db = GQLDB() # connect to Google BigTable
session.connect(request, response, db=db) # and store sessions
there
##
db.define_table('testtable',SQLField('testfield1','string'),SQLField
('testfield2','string'))
db.testtable.testfield1.requires=IS_NOT_EMPTY()

from gluon.tools import Mail, Auth, Crud # new in web2py 1.56
auth=Auth(globals(),db) # authentication/
authorization
auth.define_tables() # creates all needed
tables
crud=Crud(globals(),db) # for CRUD helpers using
auth
crud.settings.update_next = URL(r=request, f='index')

Controller
------------
def index():
session.action = ""
redirect(URL(r=request,f='testdata'))

@auth.requires_login()
def testdata():
setsubmit()
if request.args: id = request.args[0]
else: id = 3 # Included for testing
if session.action == "create":
return dict(form=crud.create(db.testtable))
elif session.action == "update":
return dict(form=crud.update(db.testtable,id))
else:
return dict(form=crud.read(db.testtable,id))

def setsubmit():
if request.vars.submit1: session.action = "create"
if request.vars.submit2: session.action = "update"
if request.vars.submit3: session.action = ""

def data():
response.view="%s/%s/%s.html" %
(request.controller,request.function, request.args[0])
return dict(form=crud())

def user():
return dict(form=auth())

Views
------
( The following is default/testdata.html )

{{extend 'layout.html'}}
<h1>Testdata
{{if session.action == "update":}}
Update
{{elif session.action == "create":}}
Add
{{pass}}
</h1>
{{=form}}
=======================================
<form action="" enctype="multipart/form-data" method="post">
<table>
<tr id="testtable_testfield1__row">
<td><label for="testtable_testfield1"
id="testtable_testfield1__label">Testfield1: </label></td>
{{if session.action in ["update","create"]:}}
<td><input class="string" id="testtable_testfield1"
name="testfield1" type="text"
value="{{=form.custom.inpval.testfield1}}" /></td>
{{else:}}
<td>{{=form.custom.inpval.testfield1}}</td>
{{pass}}
<td></td>
</tr>
<tr>
<td><label >Testfield2:</label></td>
{{if session.action in ["update","create"]:}}
<td><input class="string" id="testtable_testfield2"
name="testfield2" type="text"
value="{{=form.custom.inpval.testfield2}}" /></td>
{{else:}}
<td>{{=form.custom.inpval.testfield2}}</td>
{{pass}}
<td></td>
</tr>
{{if session.action == "update":}}
<tr id="delete_record__row">
<td><label for="delete_record" id="delete_record__label">Check to
delete:</label></td>
<td><input class="delete" id="delete_record"
name="delete_this_record" type="checkbox" value="on" /></td>
<td></td>
</tr>
{{pass}}
</table>
{{include 'buttons.html'}}

( The following is buttons.html)

<br />
{{if session.action in ["update","create"]:}}
<input type="submit" name="submit" value="Submit" />
<input type="submit" name="submit3" value="Cancel" />
{{else:}}
<input type="submit" name="submit1"
value="&nbsp;&nbsp;Add&nbsp;&nbsp;&nbsp;" />
<input type="submit" name="submit2" value="Update" />
<input type="submit" name="submit3" value="Cancel" />
{{pass}}
{{=form.hidden_fields()}}

++++++++++++++ End of MVC ++++++++++++++++++++

Thanks again to all.

Regards,
Gary

dlypka

unread,
May 3, 2009, 3:21:59 PM5/3/09
to web2py Web Framework
OK I have reproduced your code on my machine.
I blanked out the First name and pressed Submit.
Then I did File .. View Source
There I can see that it generates
<div class="error" id="testfield1__error">cannot be empty!</div>

So we 'simply' have to scour the web2py source code to look for where
the CRUD and or FORM framework code
generates a <div class="error" ... Then we need to figure out what it
needs to make that happen..

dlypka

unread,
May 3, 2009, 3:36:36 PM5/3/09
to web2py Web Framework
OK I found it (I believe) in (assuming you have downloaded the web2py
sourcecode)

\web2py\gluon\html.py line 744:

def xml(self):
name = self.attributes.get('_name', None)
if name and hasattr(self, 'errors') and self.errors.get(name,
None):
return DIV.xml(self) + DIV(self.errors[name],
_class='error', errors=None, _id='%s__error' % name).xml()
else:
return DIV.xml(self)

So it looks like we must satisfy
hasattr(self, 'errors')

But it looks like all this code is part of
class INPUT(DIV):

So it looks like you must generate the form using those HTML function
calls if you want that error code to kick in.
I guess that when the auto CRUD is used, it uses these HTML classes to
generate the form and so that is why the error message works in that
case.

On May 3, 2:51 pm, Gary <gary.k.ma...@gmail.com> wrote:

dlypka

unread,
May 3, 2009, 3:51:33 PM5/3/09
to web2py Web Framework
Since generating forms thru those HTML class methods is not too much
fun,
I believe we could continue along your solution path by making some
changes
to those classes so that we can create an instance of class INPUT to
generate ONLY the input tags
So in this scenario you would slightly change your markup to just
replace the handcode <input> tags by something like
{{ INPUT(_type='text',_name='name',value='Max').xml()}}
> > Gary- Hide quoted text -

dlypka

unread,
May 3, 2009, 4:09:21 PM5/3/09
to web2py Web Framework
The idea of replacing the handcoded <input> tag by a call to a
framework 'control'
is basically parallel to the situation when coding a ASP.NET page:
the developer has to choose between
hand-coding an <input> tag
OR
coding an ASP.NET control, which in this case would be <ASP:TextBox
id="myTextBox" name="myTextBoxName" ...

Most developers would choose the <ASP:TextBox> because it has enhanced
functionality provided by .NET, beyond what <input> provides.

So basically, the INPUT class here is what would be called a 'control'
in ASP.NET.

So looks like it would be usefully to formally define the concept of
web2py 'controls'..
Maybe we could use another word instead of 'control' - maybe
'wig2py'?

'wig2py' would be a subframework of widgets within web2py which can be
directly embedded in the markup
and which in most cases can replace standard html tags to provide
enhanced functionality such as working
with the CRUD code to provide automatic field - level error messages.
> > - Show quoted text -- Hide quoted text -

Gary

unread,
May 3, 2009, 5:19:08 PM5/3/09
to web2py Web Framework
Thank you for your detailed reply. I hope I'm not opening a can of
worms.

Being a relative newbie to both Python and Web2py, reading your
explanation makes sense to my elementary level. wish I had a higher
lever of Python competence. What I don't understand is, with the
exception of formatting (additional cr's and indentation), the
generated html code is the same as the custom html code. Without
additional code embedded in the form, how would the 'hasattr' be
satisfied by the {{=form}} but not the custom html?

Thanks,
Gary

Gary

unread,
May 3, 2009, 5:19:29 PM5/3/09
to web2py Web Framework
Thank you for your detailed reply. I hope I'm not opening a can of
worms.

Being a relative newbie to both Python and Web2py, reading your
explanation makes sense to my elementary level. wish I had a higher
lever of Python competence. What I don't understand is, with the
exception of formatting (additional cr's and indentation), the
generated html code is the same as the custom html code. Without
additional code embedded in the form, how would the 'hasattr' be
satisfied by the {{=form}} but not the custom html?

Thanks,
Gary


On May 3, 4:09 pm, dlypka <dly...@gmail.com> wrote:

dlypka

unread,
May 3, 2009, 6:32:32 PM5/3/09
to web2py Web Framework
because **inside** the crud() call I believe it (magically) does
this kind of stuff:

def test():
f = FORM('Is web2py cool? Why?',
SELECT(OPTION('Yes', _value='y'), OPTION('No',
_value='n'), _name='opts', requires=IS_IN_SET(['y'],
error_message='Errr...wrong answer')),
INPUT(_type='text', _name='why', _value="'cause python
rules", requires=IS_NOT_EMPTY()),
INPUT(_type='submit', _name='btnSubmit', _value='ok'))
if f.accepts(request.vars):
response.flash = 'form accepted'
elif request.vars.btnSubmit:
response.flash = 'error in form'
return dict(myform=f, v=request.vars)


so in particular crud() generates those INPUT objects for you, and the
INPUT object is the thing which
creates the error attribute inside that INPUT object instance which
then satisfies 'hasattr()' So I believe the solution for you is to
make an INPUT call yourself within the markup, in {{ }} (somehow).
Probably we need to modify the INPUT class Python code
to support that. Basically you need to bind your own instance of an
INPUT class, to the part of your form where you need the <input> tag.


On May 3, 5:19 pm, Gary <gary.k.ma...@gmail.com> wrote:

Álvaro Justen [Turicas]

unread,
May 3, 2009, 7:48:21 PM5/3/09
to web...@googlegroups.com
On Sun, May 3, 2009 at 7:32 PM, dlypka <dly...@gmail.com> wrote:
>
> because **inside**  the crud()  call I believe it (magically) does
> this kind of stuff:
>
> def test():
>    f = FORM('Is web2py cool? Why?',
>            SELECT(OPTION('Yes', _value='y'), OPTION('No',
> _value='n'), _name='opts', requires=IS_IN_SET(['y'],
> error_message='Errr...wrong answer')),
>            INPUT(_type='text', _name='why', _value="'cause python
> rules", requires=IS_NOT_EMPTY()),
>            INPUT(_type='submit', _name='btnSubmit', _value='ok'))
>    if f.accepts(request.vars):
>        response.flash = 'form accepted'
>    elif request.vars.btnSubmit:
>        response.flash = 'error in form'
>    return dict(myform=f, v=request.vars)
>
>
> so in particular crud() generates those INPUT objects for you, and the
> INPUT object is the thing which
> creates the error attribute inside that INPUT object instance which
> then satisfies 'hasattr()'  So I believe the solution for you is to
> make an INPUT call yourself within the markup, in {{ }} (somehow).
> Probably we need to modify the INPUT class Python code
> to support that.  Basically you need to bind your own instance of an
> INPUT class, to the part of your form where you need the <input> tag.

Crud uses SQLFORM to generate forms and SQLTABLE to present data. See
gluon/tools.py, class Crud and tools/sqlhtml.py, classes SQLFORM and
SQLTABLE.

dlypka

unread,
May 3, 2009, 8:16:11 PM5/3/09
to web2py Web Framework
The objects in gluon/html.py appear to be what I would call 'controls'
whereas the objects in gluon\sqlhtml.py are 'widgets'.

So I see that Crud uses controls and SQLFORM uses widgets.

I am hoping to find a way to use a control in the View markup rather
than in the Controller.
I believe that is what Gary needs to do.

On May 3, 7:48 pm, Álvaro Justen [Turicas] <alvarojus...@gmail.com>
wrote:
>  http://www.peta5.com.br/- Hide quoted text -

dlypka

unread,
May 3, 2009, 8:59:58 PM5/3/09
to web2py Web Framework
FYI
If someone tries to run your code on a fresh empty db,
then they need to first
create a record in the database
and im that case, the record would have id=1
and so in your code

def testdata():
setsubmit()
if request.args: id = request.args[0]
else: id = 3 # Included for testing

It should be

def testdata():
setsubmit()
if request.args: id = request.args[0]
else: id = 1 # default to read the first record
> >  http://www.peta5.com.br/-Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -

Gary

unread,
May 3, 2009, 9:15:27 PM5/3/09
to web2py Web Framework
Folks,

I've taken note of your comments and work to help me with this.
Although I'm afraid that I don't have the skills to participate, I
really appreciate your efforts.

Kindest regards,
Gary
> > >  http://www.peta5.com.br/-Hidequoted text -

dlypka

unread,
May 3, 2009, 10:13:02 PM5/3/09
to web2py Web Framework
Well you've done me a great service by creating this sample.

I went a bit further and got some partial success by just changing
this one line:

<tr id="testtable_testfield1__row">
<td>
<label for="testtable_testfield1"
id="testtable_testfield1__label">Testfield1: </label>
</td>
{{if session.action == "update":}}
<td>

{{ =INPUT(_type='text', _id='testtable_testfield1',
_name='testfield1', value="abc", requires=IS_NOT_EMPTY())}} <---
This is the changed line

</td>
{{elif session.action == "create":}}


This now causes both 'testfield1' fields to mirror each other.
Well, now we have 2 fields with the same name 'testfield1', so that is
not too great.
We would need a way to tell CRUD to NOT call INPUT
I also have not figured out how to set value = to the actual current
field value.

I'll keep working at it in my spare time..
> > > >  http://www.peta5.com.br/-Hidequotedtext -

Gary

unread,
May 3, 2009, 10:46:00 PM5/3/09
to web2py Web Framework
To see where I'm going with this, I've modified the controller to use
the base read/create/update controller (setsubmit) so it can be used
with a minimum of new code. Here is the new version adding a
controller 'authdata' for the auth_user table:

def index():
session.action = "update"
# redirect(URL(r=request,f='testdata'))
redirect(URL(r=request,f='authdata'))

@auth.requires_login()
def testdata():
if request.args: id = request.args[0]
else: id = 3 # Included for testing
x = eval(setsubmit("testtable"))
return dict(form=x)

@auth.requires_login()
def authdata():
if request.args: id = request.args[0]
else: id = 1 # Included for testing
x = eval(setsubmit("auth_user"))
return dict(form=x)

def setsubmit(table):
if request.vars.submit1: session.action = "create"
if request.vars.submit2: session.action = "update"
if request.vars.submit3 or request.vars.submit4: session.action =
"read"
cmd = "crud."+session.action+"(db."+table
if session.action in ['read','update']:
cmd += ",id)"
else:
cmd += ")"
return cmd

def data():
response.view="%s/%s/%s.html" %
(request.controller,request.function, request.args[0])
return dict(form=crud())

def user():
return dict(form=auth())

Although I'm sure this can be improved (maybe by using response.form
and passing the table name), by adding a just the controller
'authdata' and creating a 'default/authdata.html custom view, the
logic works for the new custom form with a minimum of effort. I
believe that a small program could be written to create a skeleton of
the view that would take most of the work out of the process. I saw
on AlterEgo at http://mdp.cti.depaul.edu/AlterEgo/default/show/82 that
Massimo built a small application to create this functionality from
SQL. I hope that this will be helpful to the project.

Regards,
Gary

PS. Here's the view (default/authdata.html) for the above:

{{extend 'layout.html'}}
<h1>Auth_data
{{if session.action == "update":}}
Update
{{elif session.action == "create":}}
Add
{{pass}}
</h1>
<form action="" enctype="multipart/form-data" method="post">
<table>
<tr id="auth_user_first_name__row">
<td><label for="auth_user_first_name"
id="auth_user_first_name__label">First Name: </label></td>
{{if session.action in ["update","create"]:}}
<td><input class="string" id="auth_user_first_name"
name="first_name" type="text"
value="{{=form.custom.inpval.first_name}}" /></td>
{{else:}}
<td>{{=form.custom.inpval.first_name}}</td>
{{pass}}
<td></td></tr>
<tr id="auth_user_last_name__row">
<td><label for="auth_user_last_name"
id="auth_user_last_name__label">Last Name: </label></td>
{{if session.action in ["update","create"]:}}
<td><input class="string" id="auth_user_last_name" name="last_name"
type="text" value="{{=form.custom.inpval.last_name}}" /></td>
{{else:}}
<td>{{=form.custom.inpval.last_name}}</td>
{{pass}}
<td></td></tr>
<tr id="auth_user_email__row"><td>
<label for="auth_user_email" id="auth_user_email__label">Email: </
label></td>
{{if session.action in ["update","create"]:}}
<td><input class="string" id="auth_user_email" name="email"
type="text" value="{{=form.custom.inpval.email}}" /></td>
{{else:}}
<td>{{=form.custom.inpval.email}}</td>
{{pass}}
<td></td></tr>
{{if session.action == "update":}}
<tr id="delete_record__row">
<td><label for="delete_record" id="delete_record__label">Check to
delete:</label></td>
<td><input class="delete" id="delete_record"
name="delete_this_record" type="checkbox" value="off" /></td>
<td></td></tr>
{{pass}}
</table>
{{include 'buttons.html'}}



dlypka

unread,
May 4, 2009, 5:43:47 AM5/4/09
to web2py Web Framework
OK, thanks, I'll see if I can modify it to work with CRUD.

John Heenan

unread,
May 4, 2009, 10:19:46 AM5/4/09
to web2py Web Framework
Gary

There is a lot easier way to approach this.

Just keep the crud action as originally designed and intended with
def data:
return dict(form=crud()

and use a SINGLE template file with a skeleton as indicated below. The
particular form action can be found from request.env.path_info. For
crud postback it MUST be incorparated back into the form tag.

There is VITAL information in
http://mdp.cti.depaul.edu/AlterEgo/default/show/205

Sample single all purpose skeletontemplate for data crud action:

{{extend 'layout.html'}}
<form enctype="multipart/form-data"
action="{{=request.env.path_info}}" method="post">

Make this template (data.html) the sole template for the crud
controller action<p>

def data: return dict(form=crud())<p>

Depending on what the crud form action is as determined from parsing
request.env.path_info use the approach in<br>
http://mdp.cti.depaul.edu/AlterEgo/default/show/205<br>
to determine how to layout the crud form<p>

<input value="{{=form.formkey}}" type="hidden" name="_formkey" />
<input value="{{=form.formname}}" type="hidden" name="_formname" />
<input type="submit" name='submit' value="Submit" />
</form>

Regards

John Heenan

John Heenan

unread,
May 4, 2009, 11:12:27 AM5/4/09
to web2py Web Framework
Gary

Here is a modifiation of the crud data.html template I have just
posted. It displays the usual crud forms for everything accept crud
create forms.

It can of course be easily modified to be even more specific for
specific table create forms.

Please give it a try. With this approach you can move gradually move
towards what you want to do.

{{extend 'layout.html'}}

{{import re
m=re.compile('/create/')}}
{{if not m.search(request.env.path_info):}}
{{=form}}
{{else:}}
<form enctype="multipart/form-data"
action="{{=request.env.path_info}}" method="post">
Make this template (data.html) the sole template for the crud
controller action<p>

def data: return dict(form=crud())<p>

Depending on what the crud form action is as determined from parsing
request.env.path_info use the approach in<br>
http://mdp.cti.depaul.edu/AlterEgo/default/show/205<br>
to determine how to layout the crud form<p>

<input value="{{=form.formkey}}" type="hidden" name="_formkey" />
<input value="{{=form.formname}}" type="hidden" name="_formname" />
<input type="submit" name='submit' value="Submit" />
</form>
{{pass}}

John Heenan

On May 5, 12:19 am, John Heenan <johnmhee...@gmail.com> wrote:
> Gary
>
> There is a lot easier way to approach this.
>
> Just keep the crud action as originally designed and intended with
> def data:
>     return dict(form=crud()
>
> and use a SINGLE template file with a skeleton as indicated below. The
> particular form action can be found from request.env.path_info. For
> crud postback it MUST be incorparated back into the form tag.
>
> There is VITAL information inhttp://mdp.cti.depaul.edu/AlterEgo/default/show/205
> ...
>
> read more »

dlypka

unread,
May 4, 2009, 12:31:46 PM5/4/09
to web2py Web Framework
Hi:

Thank you for this, but I am still not clear on what to code
precisely.

What exactly needs to be done to satisfy this requiurement:
"Make this template (data.html) the sole template for the crud
controller action"

Why does the controller have
def data: return dict(form=crud()) when the variable 'form' would not
be used in the View, since a custom view is to be used instead?
i.e. could we just write
def data: return dict(=crud()) ??

Where is the code which 'overrides' the auto-generated CRUD form to
point to a custom view?
Where is the markup to support the error DIV within the custom view,
to support calls from CRUD to INPUT._validate()?

Thank you.
> ...
>
> read more »- Hide quoted text -

Yarko Tymciurak

unread,
May 4, 2009, 1:57:10 PM5/4/09
to web...@googlegroups.com
On Mon, May 4, 2009 at 11:31 AM, dlypka <dly...@gmail.com> wrote:

Hi:

Thank you for this, but I am still not clear on what to code
W
.....
hy does the controller have
 def data: return dict(form=crud()) when the variable 'form' would not
be used in the View, since a custom view is to be used instead?
i.e. could we just write
 def data: return dict(=crud()) ??


sounds like you need to see this, visualize this:  use the shell:

python web2py.py -S myapp -M

>>> # don't worry about passing to a view - see what happens:
>>> form=crud()
>>> # now the view has a variable "form" - what does it contain?
>>> print form
>>> type( form )
>>> dict( form )

I hope you're getting the idea.

You could also grab a copy of WingIDE form www.wingware.com - I haven't used to free "101" version, but I think you can inspect local variables the same way -  so to do this there, set a breakpoint,
in your function, separate the assignment from the return (so it is easier to inspect  little by little what is going on), e.g.:

def my_controller_function:
  # ... stuff....
  form=crud()  # now you can stop and inspect all the elements of this
  send_to_view = dict( form )
  return send_to_view

See if that helps you...

John Heenan

unread,
May 4, 2009, 2:12:23 PM5/4/09
to web2py Web Framework
Answers below

On May 5, 2:31 am, dlypka <dly...@gmail.com> wrote:
> Hi:
>
> Thank you for this, but I am still not clear on what to code
> precisely.
>
> What exactly needs to be done to satisfy this requiurement:
>   "Make this template (data.html) the sole template for the crud
>   controller action"
>

If the controller function below is in file controllers\default.py
def data():
return dict(form=crud())

then put the suggested contents for its template file in file
views\default\data.html


> Why does the controller have
>  def data: return dict(form=crud()) when the variable 'form' would not
> be used in the View, since a custom view is to be used instead?
> i.e. could we just write
>  def data: return dict(=crud()) ??

It is up to you as to what you do with the name 'form' in a custom
form. The generic template displays it but a custom template does not
need to display this name, only to display what it chooses to extract
form the object that the name represents.

The name is arbitrary but is required for the way the python dict
function works. Try it with any name you want, as long as you use a
name. For example
def data: return dict(testform=crud())

Remember to make sure your template knows what name to expect to
extract information with and to avoid messy tests to determine it.

>
> Where is the code which 'overrides' the auto-generated CRUD form to
> point to a custom view?

Nothing is overriden with this approach, not even the default template
name. If the default template does not exist then the generic template
is used. The generic tempate uses the BEAUTIFY helper which has clever
tricks that use recursion to traverse information passed. By the time
recursion has popped back out again a nice representation has been
constructed!

> Where is the markup to support the error DIV within the custom view,
> to support calls from CRUD to INPUT._validate()?
>

The crud class does all the messy plumbing for you. For a create form
a SQLFORM is used and for the postback a if form.accept test is
conducted. If the test passes data is saved ot the database. If the
test fails the form is shown again with indications of where
validation failed.

If validation fails then forms.error is filled in and is used to
populate the error DIVs.

> Thank you.

Your welcome
> ...
>
> read more »

dlypka

unread,
May 4, 2009, 8:51:41 PM5/4/09
to web2py Web Framework
Thanks so much again.

I pasted in the bits of code you demonstrated, which I was missing
and voila, now the validation works with crud() using Gary's custom
form!

dlypka

unread,
May 4, 2009, 9:29:26 PM5/4/09
to web2py Web Framework
Thanks again John.

I was able to piece together snippets from your example and
that made our sample work for crud update finally.
It correctly validates the empty field and displays the error message.

The 3 fixes I made were

1. The hidden fields at the bottom helped, I believe:
<input value="{{=form.formkey}}" type="hidden" name="_formkey" />
<input value="{{=form.formname}}" type="hidden" name="_formname" /
>

2.
<form action=="{{=request.env.path_info}}" <-- I was missing that
code in the ""

3.
in the Controller, the key important logic for the case of a crud
update was
elif session.action == "update":
id=request.args[0]
response.view="%s/%s/%s.html" %
(request.controller,request.function, request.args[0])
return dict(form=crud.update(db.testtable,id))

mdipierro

unread,
May 4, 2009, 9:39:14 PM5/4/09
to web2py Web Framework


On May 4, 8:29 pm, dlypka <dly...@gmail.com> wrote:
> Thanks again John.
>
> I was able to piece together snippets from your example and
> that made our sample work for crud update finally.
> It correctly validates the empty field and displays the error message.
>
> The 3 fixes I made were
>
> 1. The hidden fields at the bottom helped, I believe:
>     <input value="{{=form.formkey}}" type="hidden" name="_formkey" />
>     <input value="{{=form.formname}}" type="hidden" name="_formname" /

or just {{=form.hidden_fields()}}

dlypka

unread,
May 5, 2009, 1:55:37 AM5/5/09
to web2py Web Framework
I really appreicate these debugging instructions.
Thank you.

On May 4, 1:57 pm, Yarko Tymciurak <yark...@gmail.com> wrote:
> On Mon, May 4, 2009 at 11:31 AM, dlypka <dly...@gmail.com> wrote:
>
> > Hi:
>
> > Thank you for this, but I am still not clear on what to code
> > W
>
> .....
>
> > hy does the controller have
> >  def data: return dict(form=crud()) when the variable 'form' would not
> > be used in the View, since a custom view is to be used instead?
> > i.e. could we just write
> >  def data: return dict(=crud()) ??
>
> sounds like you need to see this, visualize this:  use the shell:
>
> python web2py.py -S myapp -M
>
> >>> # don't worry about passing to a view - see what happens:
> >>> form=crud()
> >>> # now the view has a variable "form" - what does it contain?
> >>> print form
> >>> type( form )
> >>> dict( form )
>
> I hope you're getting the idea.
>
> You could also grab a copy of WingIDE formwww.wingware.com- I haven't used

Gary

unread,
Jun 4, 2009, 10:28:16 PM6/4/09
to web2py Web Framework
Thank you so much for your help 'offline'. I know that this got more
involved than either of us thought. I really appreciate your efforts.

Regards,
Gary


On May 4, 5:43 am, dlypka <dly...@gmail.com> wrote:
> OK, thanks, I'll see if I can modify it to work with CRUD.
>
> > > > > > I believe that is whatGaryneeds to do.
Reply all
Reply to author
Forward
0 new messages