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 < ml.richard.vez...@gmail.com> 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 < > ml.richard.vez...@gmail.com> 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 <abasta...@gmail.com> 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 >>>> >>>> >>>> >> >