Update_record and validator conflict.

127 views
Skip to first unread message

annet

unread,
Mar 7, 2011, 4:17:09 AM3/7/11
to web2py-users
In db.py I defined the following table:

db.define_table('company',
Field('name',length=54,default='',notnull=True),
Field('CoC_number',length=8),
Field('subdossiernumber',length=4,default='0000'),
...
Field(...),
migrate=False)

db.company.CoC_number.requires=IS_NOT_IN_DB(db(db.company.subdossiernumber==request.vars.subdossiernumber),db.company.CoC_number,error_message='combination
of CoC-number and subdossiernumber already in database')


In a controller I defined one form to update multiple tables. Here are
the parts related to the company table:

def update():
id= request.args(0)
### retrieve company data
company=db(db.company.id==id).select(db.company.ALL)
### create form
form=SQLFORM.factory(db.bedrijf,...,...)
### pre-populate form
if company:
form.vars.name=company[0].name
form.vars.CoC_number=company[0].CoC_number
form.vars.subdossiernumber=company[0].subdossiernumber
...
if form.accepts(request.vars,session):

company.update_record(**db.bedrijf._filter_fields(form.vars))
...
session.flash='Records updated'
redirect(URL(r=request,f='retrieve',args=id))
elif form.errors:
response.flash=response.flash_formerror
return dict(form=form)

When I execute the function the data is retrieved, the form is created
and pre-populated, however, when I click the submit button, the
validator on the Coc_number and subdossiernumber field prevents the
record from being updated and displays the error_message: 'combination
of CoC-number and subdossiernumber already in database'

I didn't expect this to happen when updating a record without changing
the CoC-number and subdossiernumber, I'd expect this to happen when I
change the CoC-number and subdossiernumber of one company to that of
another company. Is there a solution to solve this problem?


Kind regards,

Annet.

villas

unread,
Mar 7, 2011, 7:41:44 AM3/7/11
to web2py-users
Hi Annet

Seems strange that you are creating a form for a real table by using
SQLFORM.factory. Why do that, rather than create a normal form? If
you created a normal form, I suspect the issue would be resolved.

You don't show the model or validators, so can't comment on those.

Regards, D

annet

unread,
Mar 7, 2011, 9:42:34 AM3/7/11
to web2py-users
Hi David,

This is the relevant part of the model file, table definition:

db.define_table('company',
Field('name',length=54,default='',notnull=True),
Field('CoC_number',length=8),
Field('subdossiernumber',length=4,default='0000'),
...
Field(...),
migrate=False)

... and the validator that's causing the problem:

db.company.CoC_number.requires=IS_NOT_IN_DB(db(db.company.subdossiernumber==request.vars.subdossiernumber),db.company.CoC_number,error_message='combination
of CoC-number and subdossiernumber already in database')


> Seems strange that you are creating a form for a real table by using
> SQLFORM.factory. Why do that, rather than create a normal form?

Because I want to use one form to update multiple tables, and from the
web2py manual: http://www.web2py.com/book/default/chapter/07#One-form-for-multiple-tables
I learned to use form=SQLFORM.formfactory(...) for that purpose.

If there's another solution for having one form to update multiple
tables, please let me know.


Kind regards,

Annet.

DenesL

unread,
Mar 7, 2011, 2:00:44 PM3/7/11
to web2py-users
Hi Annet,

when you use SQLFORM to update a record you supply the record or the
record id, so web2py can retrieve it for you. The IS_NOT_IN_DB
validator checks against the record id so updates don't get a
validation error.

Since SQLFORM.factory does not allow you to supply the record or
record id it can not be used as is. But you can modify the validator
before the accepts to skip the error for the particular record you are
using, as shown below. Note: AFAIK this is undocumented, so it may
change in the future.

On Mar 7, 4:17 am, annet <annet.verm...@gmail.com> wrote:
> In db.py I defined the following table:
>
> db.define_table('company',
> Field('name',length=54,default='',notnull=True),
> Field('CoC_number',length=8),
> Field('subdossiernumber',length=4,default='0000'),
> ...
> Field(...),
> migrate=False)
>
> db.company.CoC_number.requires=IS_NOT_IN_DB(db(db.company.subdossiernumber==request.vars.subdossiernumber),db.company.CoC_number,error_message='combination
> of CoC-number and subdossiernumber already in database')
>
> In a controller I defined one form to update multiple tables. Here are
> the parts related to the company table:
>
> def update():
> id= request.args(0)
> ### retrieve company data
> company=db(db.company.id==id).select(db.company.ALL)
> ### create form
> form=SQLFORM.factory(db.bedrijf,...,...)
> ### pre-populate form
> if company:

# this is undocumented
db.company.CoC_number.requires.set_self_id(company[0].id)

> form.vars.name=company[0].name
> form.vars.CoC_number=company[0].CoC_number
> form.vars.subdossiernumber=company[0].subdossiernumber
> ...
> if form.accepts(request.vars,session):
>
> company.update_record(**db.bedrijf._filter_fields(form.vars))

# this should be:
company[0].update_record(**db.company._filter_fields(form.vars))

villas

unread,
Mar 7, 2011, 7:20:03 PM3/7/11
to web2py-users
>           # this is undocumented
>           db.company.CoC_number.requires.set_self_id(company[0].id)

Denes, Thanks for showing us this! We should have an 'official'
method to do this, it is an important feature.

annet

unread,
Mar 9, 2011, 4:03:30 AM3/9/11
to web2py-users
Hi Denes,

Thanks for your reply. I tried:

>           # this is undocumented
>           db.company.CoC_number.requires.set_self_id(company[0].id)
>
> >         form.vars.name=company[0].name
> >         form.vars.CoC_number=company[0].CoC_number
> >         form.vars.subdossiernumber=company[0].subdossiernumber
> >         ...
> >         if form.accepts(request.vars,session):


... and got this error ticket:

Traceback (most recent call last):
File "/Library/Python/2.5/site-packages/web2py_1.87.3/gluon/
restricted.py", line 188, in restricted
exec ccode in environment
File "/Library/Python/2.5/site-packages/web2py_1.87.3/applications/
cms/controllers/myadmin.py", line 262, in <module>
File "/Library/Python/2.5/site-packages/web2py_1.87.3/gluon/
globals.py", line 96, in <lambda>
self._caller = lambda f: f()
File "/Library/Python/2.5/site-packages/web2py_1.87.3/gluon/
tools.py", line 2237, in f
return action(*a, **b)
File "/Library/Python/2.5/site-packages/web2py_1.87.3/applications/
cms/controllers/myadmin.py", line 180, in update
db.company.CoC_number.requires.set_self_id(company[0].id)
AttributeError: 'list' object has no attribute 'set_self_id'


... do you know why?


Kind regards,

Annet.

DenesL

unread,
Mar 9, 2011, 5:35:17 AM3/9/11
to web2py-users
Hi Annet,

the requires for the field is now a list of validators for some
reason.
You have to use the set_self_id only on the IS_NOT_IN_DB portion of
the requires.

Did you change the requires?.
If not, then it is probably just a one member list so you can do

db.company.CoC_number.requires[0].set_self_id(company[0].id)

DenesL

unread,
Mar 9, 2011, 7:57:38 AM3/9/11
to web2py-users

Or better yet, store the validator object in a variable and use that:

isnotindb=IS_NOT_IN_DB(...)
db.company.CoC_number.requires=isnotindb

and in the action:

isnotindb.set_self_id(company[0].id)

then it does not matter if the field uses more validators, since you
could for example do:

db.company.CoC_number.requires=[IS_NOT_EMPTY(),isnotindb]

and the statement with set_self_id would still work.

annet

unread,
Mar 11, 2011, 5:56:23 AM3/11/11
to web2py-users
Hi Denes,

> Or better yet, store the validator object in a variable and use that:

Thanks for providing me with this solution, problem solved and
something learned again.


Kind regards,

Annet.
Reply all
Reply to author
Forward
0 new messages