IS_IN_SET doesn't produce dropdown if IS_NOT_IN_DB also required

129 views
Skip to first unread message

Fran

unread,
Dec 1, 2008, 6:42:45 PM12/1/08
to web2py Web Framework
I want to restrict a field to just a few specific options.
Only 1 record should exist for each option.
So I need both sets of requires.

The vlaidation works fine, however the form generated (in T2 at least)
isn't the expected dropdown, but rather a straight textbox.
Is this a bug?
Meanwhile, is there a way of forcing the dropdown?

Many thanks,
Fran.

mdipierro

unread,
Dec 1, 2008, 6:48:09 PM12/1/08
to web2py Web Framework
did you set requires=IS_IN_DB(....) without the [ ] ?

Fran

unread,
Dec 1, 2008, 7:17:00 PM12/1/08
to web2py Web Framework
> did you set requires=IS_IN_DB(....) without the [ ] ?

db.gis_key.service.requires=[IS_IN_SET
(['google','multimap','yahoo']),IS_NOT_IN_DB(db,'gis_key.service')]

mdipierro

unread,
Dec 1, 2008, 7:36:11 PM12/1/08
to web2py Web Framework
A list of validators will not give you a dropdown. These will:

db.gis_key.service.requires=IS_IN_SET(['google','multimap','yahoo'])

db.gis_key.service.requires=IS_NOT_IN_DB(db,'gis_key.service')

Massimo

mdipierro

unread,
Dec 1, 2008, 7:41:13 PM12/1/08
to web2py Web Framework
I believe you want:

options=[x for x in ['google','multimap','yahoo'] if not db
(db.gis_key.sevice==x).count()]
db.gis_key.service.requires=IS_IN_SET(options)

Massimo

Fran

unread,
Dec 2, 2008, 2:46:57 AM12/2/08
to web2py Web Framework
1st option failed, but 2nd option works beautifully - many thanks! :)

Fran

unread,
Dec 2, 2008, 2:56:04 AM12/2/08
to web2py Web Framework
Actually, no - 2nd option doesn't work when doing this:
item=t2.update(db.gis_key)

I'm editing the key for the 'google' service, but now my form only has
the 2 other options in the dropdown! (just as if I were entering a
brand new key)

I tried to workaround the issue by not making the service field
editable:
item=t2.update(db.gis_key,fields=['key'])

However this isn't supported by t2.update()

Suggestions welcomed :)

Jonathan Benn

unread,
Dec 2, 2008, 7:37:14 AM12/2/08
to web2py Web Framework
Hi Fran,


On Dec 2, 10:56 am, Fran <francisb...@googlemail.com> wrote:

> Suggestions welcomed :)

It sounds to me like you need to mess with this line of code until it
gives you the result you want:
options=[x for x in ['google','multimap','yahoo'] if not db
(db.gis_key.sevice==x).count()]

I'm not sure what the exact result is that you want. From your
description it sounds to me like you're getting the result you want,
so I'm confused. If you can give more detail about (1) exactly what
effect you want, and (2) what you are getting instead, then that would
help a lot.


Sincerely,

--Jonathan

Jonathan Benn

unread,
Dec 2, 2008, 7:47:07 AM12/2/08
to web2py Web Framework
Hi Massimo,


On Dec 2, 3:36 am, mdipierro <mdipie...@cs.depaul.edu> wrote:

>  A list of validators will not give you a dropdown.

When you say that a list of validators will not give a dropdown, is
this a fundamental limitation of web2py, meaning that it cannot be
done within the architecture? Or is it a minor issue that will be
fixed?


Thanks,

--Jonathan

Fran

unread,
Dec 2, 2008, 10:26:30 AM12/2/08
to web2py Web Framework
Thanks Jonathan.

What I want:
gis_key.service should be from the following SET:
google,multimap,yahoo
There should only be a maximum of 1 gis_key.key for each of these
services.
I therefore need more than just IS_IN_SET() as that allows multiple
keys per service.

options=[x for x in ['google','multimap','yahoo'] if not db
(db.gis_key.sevice==x).count()]

This works well when adding a new key as I get all 3 options visible
in a dropdown unless I have an entry already, in which case I just get
the remaining two.
However it doesn't work when editing an existing entry (via t2.update)
since I still just get only entries available to me which are not yet
set in the database, when the usual result desired would be to change
just the key, but leave the service as-is.

I could look into solutions which have only part of the validation
done in the Model (either the IS_IN_SET or the IS_NOT_IN_DB) & do the
rest in a mixture of the Controller & the View, but this would
obviously mean a lot more work...

mdipierro

unread,
Dec 2, 2008, 10:35:11 AM12/2/08
to web2py Web Framework
I think you should create your on validator. This seems a very
specific problem.

Massimo

Fran

unread,
Dec 2, 2008, 4:25:00 PM12/2/08
to web2py Web Framework
ok, shame as this then makes the app less portable...however if this
is the only way.
Can you give me a pointer about how to ensure that I still get the
dropdown in the generated forms?

tx

mdipierro

unread,
Dec 2, 2008, 4:41:10 PM12/2/08
to web2py Web Framework
look into gluon/validators.py and specifically into IS_IN_SET

make in your model (so that it will be portable) similar to IS_IN_SET

as long has it has an options method, it will make the dropdown.

Massimo

Fran

unread,
Dec 2, 2008, 4:51:57 PM12/2/08
to web2py Web Framework
Would it not be generically useful to be able to hide fields from the
t2-generated view tables/edit forms?
I have a desire to do this in another area of my app too.

I have a table 'gis_layer' which needs many different attributes, but
not all are relevant to all gis_layer.type's
I looked at 1st at separating out the fields which are only relevant
to specific type's (linked by a layer_id foreign key), but I ended up
with many separate linked tables & trying to get a whole layer viewed/
edited in 1 place was proving very hard as was ensuring there was
referential integrity. (I tried Left Joins)
It also appears to break the idea that each entity should exist in a
single table.
Suggestions on how best to approach this issue also welcomed :)

mdipierro

unread,
Dec 2, 2008, 5:02:09 PM12/2/08
to web2py Web Framework
This is exaplined in the t2.pdf (db.table.exposes=[...])

Fran

unread,
Dec 2, 2008, 5:27:21 PM12/2/08
to web2py Web Framework
> This is explained in the t2.pdf (db.table.exposes=[...])

Lovely, yes :)
It's not possible to set this conditionally within a Controller,
though, is it?
- or even within a View

I want to change which fields are displayed depending on the contents
of some of the fields...

mdipierro

unread,
Dec 2, 2008, 5:33:04 PM12/2/08
to web2py Web Framework
Yes you can do it anywhere.

Massimo

Fran

unread,
Dec 2, 2008, 5:52:16 PM12/2/08
to web2py Web Framework
> Yes you can do it anywhere.

Awesome, this is very cool - I'm enjoying this framework more & more :)

DenesL

unread,
Dec 2, 2008, 11:52:25 PM12/2/08
to web2py Web Framework
Fran, the following validator seems to work as per your needs:

class THIS_NOT_IN_DB(object):
def __init__(self,dbset,field,this,error_message='value already in
database!'):
if hasattr(dbset,'define_table'): self.dbset=dbset()
else: self.dbset=dbset
self.field=field
self.value=this
self.error_message=error_message
self.record_id=0
def set_self_id(self,id): self.record_id=id
def __call__(self,value):
tablename,fieldname=str(self.field).split('.')
field=self.dbset._db[tablename][fieldname]
rows=self.dbset(field==self.value).select(limitby=(0,1))
if len(rows)>0 and str(rows[0].id)!=str(self.record_id):
return (self.value,self.error_message)
return (value,None)

example:
db.define_table('gis',
SQLField('key'),
SQLField('service')
)
db.gis.key.requires=THIS_NOT_IN_DB(db
(db.gis.service==request.vars.service),'gis.service',request.vars.service,'service
already in use')
db.gis.service.requires=IS_IN_SET(['google','multimap','yahoo'])

so the validation of one field (key) depends on the value of another
(service).

Fran

unread,
Dec 3, 2008, 2:50:18 AM12/3/08
to web2py Web Framework
> Fran, the following validator seems to work as per your needs:

This looks really nice - many thanks!
Also looks generic enough to be worth including in Web2Py core
(Massimo?)
[Although I'm wondering whether it could still be worth adding the
ability to package custom validators within an application to keep
them portable. I guess the modules directory could be used for this so
having a 'validators_custom.py' in that folder which gets hooked in
sounds useful to me...]

However if I put this into my db.py it fails:

Traceback (most recent call last):
File "C:\Bin\web2py\gluon\restricted.py", line 62, in restricted
exec ccode in environment
File "C:\Bin\web2py\applications\sahana/models/db.py", line 107, in
<module>
db.gis.key.requires=THIS_NOT_IN_DB(db
(db.gis.service==request.vars.service),'gis.service',request.vars.service,'service
already in use')
File "C:\Bin\web2py\gluon\validators.py", line 763, in __init__
field=self.dbset._db[tablename][fieldname]
NameError: global name 'tablename' is not defined

I've looked into the code & the only reason that I can think this
would be the case is that request.vars.service is blank.
I've tried to test this by appending a '?service=google' to the end of
the URL but it still fails.
I also tried moving this advanced validation to the controller or even
view without luck...

DenesL

unread,
Dec 3, 2008, 9:31:47 AM12/3/08
to web2py Web Framework
Fran, the code above was just an example.
You have to adapt the validator parameters to your own model, i.e. you
don't have a 'gis' table.

Fran

unread,
Dec 3, 2008, 10:01:32 AM12/3/08
to web2py Web Framework
> Fran, the code above was just an example.
> You have to adapt the validator parameters to your own model, i.e. you
> don't have a 'gis' table.

Yup, I spotted that ;)
I originally tried changing it to my data then when I thought I must
be mistranslating, then I created a table exactly as defined in your
helpful post...however even 100% following what you'd written gave
exactly this same error.
Have tried a few variations with no success either.
It does seem to be a basis for solving my problem in a nice, generic
way, though :)

F

DenesL

unread,
Dec 3, 2008, 10:51:54 AM12/3/08
to web2py Web Framework
tablename is created from the field parameter,
if your field is 'gis_key.service' then tablename='gis_key'

Your model should have something like:
db.gis_key.key.requires=THIS_NOT_IN_DB(db
(db.gis_key.service==request.vars.service),'gis_key.service',request.vars.service,'service
already in use')

but I can't say for sure since I haven't seen your model.

Where did you place the validator code?.
You can even have it in your model.
Reply all
Reply to author
Forward
0 new messages