I try to hack a bit with IS_IN_DB to include a "ornull=" option that give
this :
class IS_IN_DB_DEV_ORNULL():
"""
example::
INPUT(_type='text', _name='name',
requires=IS_IN_DB(db, db.mytable.myfield, zero=''))
used for reference fields, rendered as a dropbox
"""
def __init__(
self,
dbset,
field,
label=None,
error_message='value not in database',
orderby=None,
groupby=None,
cache=None,
multiple=False,
zero='',
sort=False,
_and=None,
ornull=None,
null=None,
):
from dal import Table
if isinstance(field,Table): field = field._id
if hasattr(dbset, 'define_table'):
self.dbset = dbset()
else:
self.dbset = dbset
self.field = field
(ktable, kfield) = str(self.field).split('.')
if not label:
label = '%%(%s)s' % kfield
if isinstance(label,str):
if regex1.match(str(label)):
label = '%%(%s)s' % str(label).split('.')[-1]
ks = regex2.findall(label)
if not kfield in ks:
ks += [kfield]
fields = ks
else:
ks = [kfield]
fields = 'all'
self.fields = fields
self.label = label
self.ktable = ktable
self.kfield = kfield
self.ks = ks
self.error_message = error_message
self.theset = None
self.orderby = orderby
self.groupby = groupby
self.cache = cache
self.multiple = multiple
self.zero = zero
self.sort = sort
self._and = _and
self.ornull = ornull
self.null = null
def set_self_id(self, id):
if self._and:
self._and.record_id = id
def build_set(self):
if self.fields == 'all':
fields = [f for f in self.dbset.db[self.ktable]]
else:
fields = [self.dbset.db[self.ktable][k] for k in self.fields]
if self.dbset.db._dbname != 'gae':
orderby = self.orderby or reduce(lambda a,b:a|b,fields)
groupby = self.groupby
dd = dict(orderby=orderby, groupby=groupby, cache=self.cache)
records = self.dbset.select(*fields, **dd)
else:
orderby = self.orderby or reduce(lambda a,b:a|b,(f for f in
fields if not f.name=='id'))
dd = dict(orderby=orderby, cache=self.cache)
records = self.dbset.select(self.dbset.db[self.ktable].ALL,
**dd)
self.theset = [str(r[self.kfield]) for r in records]
if isinstance(self.label,str):
self.labels = [self.label % dict(r) for r in records]
else:
self.labels = [self.label(r) for r in records]
def options(self):
self.build_set()
items = [(k, self.labels[i]) for (i, k) in enumerate(self.theset)]
if self.sort:
items.sort(options_sorter)
if self.zero != None and not self.multiple:
items.insert(0,('',self.zero))
return items
def __call__(self, value):
unused_value, empty = is_empty(value)
"""if self.multiple:
if isinstance(value,list):
values=value
elif value:
values = [value]
else:
values = []
if isinstance(self.multiple,(tuple,list)) and \
not self.multiple[0]<=len(values)<self.multiple[1]:
return (values, translate(self.error_message))
if not [x for x in values if not x in self.theset]:
return (values, None)
elif self.theset:
if value in self.theset:
if self._and:
return self._and(value)
else:
return (value, None)"""
if self.ornull:
if self.multiple:
if isinstance(value,list):
values=value
elif value:
values = [value]
else:
values = []
if isinstance(self.multiple,(tuple,list)) and \
not self.multiple[0]<=len(values)<self.multiple[1]:
return (values, translate(self.error_message))
if not [x for x in values if not x in self.theset]:
return (values, None)
elif self.theset:
if value in self.theset:
if self._and:
return self._and(value)
else:
return (value, None)
if empty:
return (self.null, None)
else:
(ktable, kfield) = str(self.field).split('.')
field = self.dbset.db[ktable][kfield]
if self.dbset(field == value).count():
if self._and:
return self._and(value)
else:
return (value, None)
return (value, translate(self.error_message))
But I am still stock with the NULL in both field that goes trought the
database overriding my ONLY_ONE_CAN_BE_FILLED() validator...
I also try to add a _and= option to my ONLY_ONE_CAN_BE_FILLED() validator,
but remove the dropbox...
The only solution that I can see now is to merge IS_IN_DB
with ONLY_ONE_CAN_BE_FILLED() that is not going to be really DRY...
If someone can see an other solution, I am really open to the idea...
Richard
On Wed, Jun 22, 2011 at 10:31 AM, Richard Vézina <
[email protected]> wrote:
> Hello Anthony,
>
> The "_and=" works perfectly and bring back the dropbox, but as you mention,
> not all the logic of the validator that I pass in the _and= option is
> working... The IS_EMPTY_OR is overriding the
>
> Here the proper syntax to get the dropbox :
>
> db.table.field1.requires =\
> IS_EMPTY_OR(IS_IN_DB(db,'table.field1'),
>
> _and=ONLY_ONE_CAN_BE_FILLED([request.vars.field2],error_message='Select only
> one')))
>
> I try to remove the IS_EMPTY_OR, but as expected the
> IS_IN_DB prevent insertion of a null...
>
> Don't know what the best option to make it works properly...
>
> Adding option to IS_EMPTY_OR() to allow inter independency with
> my ONLY_ONE_CAN_BE_FILLED() or make a _and= option to
> my ONLY_ONE_CAN_BE_FILLED() to make it works with IS_IN_DB??
>
> Richard
>
> On Tue, Jun 21, 2011 at 9:11 PM, Richard Vézina <
> [email protected]> wrote:
>
>> Great thanks Anthony, I will try that tomorrow first time and I will
>> report back.
>>
>> Richard
>>
>>
>> On Tue, Jun 21, 2011 at 5:35 PM, Anthony <[email protected]> wrote:
>>
>>> When you need to use additional validators with IS_IN_DB but still want
>>> the dropbox, you can add the additional validators to the IS_IN_DB validator
>>> via its '_and' argument -- see
>>> http://web2py.com/book/default/chapter/07#Database-Validators. However,
>>> I'm not sure if that works when IS_IN_DB is inside an IS_NULL_OR validator.
>>> (Actually, IS_NULL_OR has been deprecated in favor of IS_EMPTY_OR.)
>>>
>>> Anthony
>>>
>>> On Tuesday, June 21, 2011 5:16:12 PM UTC-4, Richard wrote:
>>>
>>>> Hello,
>>>>
>>>> I would like to know if the problem I face coming from the validator
>>>> that I write or is a IS_IN_DB behavior in case of multiple validators??
>>>>
>>>> Here my validator :
>>>>
>>>> class ONLY_ONE_CAN_BE_FILLED(object)**:
>>>> """Class representing a validator requiring at least one non-empty
>>>> field in a set. """
>>>> def __init__(
>>>> self,
>>>> others,
>>>> error_message='Enter a value in at least one field'
>>>> ):
>>>> self.others = others
>>>> self.error_message = error_message
>>>>
>>>> def __call__(self, value):
>>>> okay = (value, None)
>>>> error = (value, self.error_message)
>>>> values = []
>>>> values.append(value)
>>>> values.extend(self.others)
>>>> empties = []
>>>> for v in values:
>>>> unused_v, empty = is_empty(v)
>>>> empties.append(empty)
>>>> if empties.count(False) == 1:
>>>> return okay
>>>> else:
>>>> return error
>>>>
>>>>
>>>> But when i use it like this I lost my dropbox for the FK field1 :
>>>>
>>>> db.table.field1.requires =\
>>>> [IS_NULL_OR(IS_IN_DB(db,'other**table.id <http://othertable.id>
>>>> ','%(fieldrepresent)s'**,orderby=('fieldrepresent'))),
>>>> ONLY_ONE_CAN_BE_FILLED([**request.vars.field2],error_**message='Select
>>>> a volume or an folder')]
>>>>
>>>> I remember I read something about IS_IN_DB and [IS_IN_DB]...
>>>>
>>>> Can I have the dropbox and the multiple validators at the same time??
>>>>
>>>> Thanks
>>>>
>>>> Richard
>>>>
>>>>
>>>>
>>
>