The list:string type does not store empty strings. Because of the way the function bar_encode() formats an empty list as ||, there's no room for empty strings in it.
But that's python and web2py.. it can't be difficult.
class EmptyStrAble(object): """ (1)Define filter_in/filter_out for the desired field and (2)wrap its `contains` operator for full functionality as a list:string able to work with empty strings """ empty_string_mark = '-*- empty string -*-' def filter_in(self, obj): """ change empty string with empty_string_mark """ if obj == '': obj = self.empty_string_mark elif hasattr(obj, '__iter__'): if '' in obj: obj[obj.index('')] = self.empty_string_mark return obj def filter_out(self, obj): """ change empty_string_mark with empty string """ if isinstance(obj, list): # it's list or None if self.empty_string_mark in obj: obj[obj.index(self.empty_string_mark)] = '' return obj def contains_wrapper(self, func): """ apply `filter_in` to the first argument of `contains` operator wich always is either a string or a list of strings """ def checker(*args, **kwargs): largs = args[:] largs[0] = self.filter_in(largs[0]) return func(*largs, **kwargs) return checker
And apply:
# ==== in models ===== db.define_table('thing', Field('options', 'list:string')) # Define filters and wrap `contains` operator esa = EmptyStringAble() db.thing.options.filter_in = lambda obj, my_in=esa.filter_in: my_in( obj ) db.thing.options.filter_out = lambda obj, my_out=esa.filter_out: my_out( obj ) db.thing.options.contains = esa.contains_wrapper( db.thing.options.contains )
Now we've got our desire satisfied:
def test_me(): db.thing.truncate() db.thing.insert(options='') db.thing.insert(options=None) db.thing.insert(options=[]) db.thing.insert(options=['a', '', 'ca']) assert(db(db.thing.options.contains('')).count()==2), 'Error' assert(db(db.thing.options.contains('', all=True)).count()==2), 'Error' assert(db(db.thing.options.contains(['', 'ca'], all=True)).count()==1), 'Error' return 'Python and Web2py rules!'
Comments (0)