diff --git a/gluon/dal.py b/gluon/dal.py index 2506e1c5..471ed657 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -54,28 +54,47 @@ def _default_validators(db, field): requires.append(validators.IS_TIME()) elif field_type == 'datetime': requires.append(validators.IS_DATETIME()) - elif db and field_type.startswith('reference') and \ - field_type.find('.') < 0 and \ - field_type[10:] in db.tables: - referenced = db[field_type[10:]] - if hasattr(referenced, '_format') and referenced._format: - requires = validators.IS_IN_DB(db, referenced._id, - referenced._format) - if field.unique: - requires._and = validators.IS_NOT_IN_DB(db, field) - if field.tablename == field_type[10:]: - return validators.IS_EMPTY_OR(requires) - return requires - elif db and field_type.startswith('list:reference') and \ - field_type.find('.') < 0 and \ - field_type[15:] in db.tables: - referenced = db[field_type[15:]] - if hasattr(referenced, '_format') and referenced._format: - requires = validators.IS_IN_DB(db, referenced._id, - referenced._format, multiple=True) - else: - requires = validators.IS_IN_DB(db, referenced._id, - multiple=True) + elif db and field_type.startswith('reference'): + if field_type.find('.') < 0 and field_type[10:] in db.tables: + referenced = db[field_type[10:]] + if hasattr(referenced, '_format') and referenced._format: + requires = validators.IS_IN_DB(db, referenced._id,referenced._format) + else: + requires = validators.IS_IN_DB(db, referenced._id) + elif field_type.find('.') > 0 and field_type[10:].split('.')[0] in db.tables: + table_field = field_type[10:].split('.') + table_name=table_field[0] + field_name=table_field[1] + referenced = db[table_name] + if hasattr(referenced, '_format') and referenced._format: + requires = validators.IS_IN_DB(db, referenced[field_name],referenced._format) + else: + requires = validators.IS_IN_DB(db, referenced[field_name]) + if field.unique: + requires._and = validators.IS_NOT_IN_DB(db, field) + if not field.notnull: + requires = validators.IS_EMPTY_OR(requires) + return requires + elif db and field_type.startswith('list:reference'): + if field_type.find('.') < 0 and field_type[15:] in db.tables: + referenced = db[field_type[15:]] + if hasattr(referenced, '_format') and referenced._format: + requires = validators.IS_IN_DB(db, referenced._id, + referenced._format, multiple=True) + else: + requires = validators.IS_IN_DB(db, referenced._id, + multiple=True) + elif field_type.find('.') > 0 and field_type[15:].split('.')[0] in db.tables: + table_field = field_type[15:].split('.') + table_name=table_field[0] + field_name=table_field[1] + referenced = db[table_name] + if hasattr(referenced, '_format') and referenced._format: + requires = validators.IS_IN_DB(db, referenced[field_name], + referenced._format, multiple=True) + else: + requires = validators.IS_IN_DB(db, referenced[field_name], + multiple=True) if field.unique: requires._and = validators.IS_NOT_IN_DB(db, field) if not field.notnull: diff --git a/gluon/tests/test_validators.py b/gluon/tests/test_validators.py index 36bf454e..dd3cc0ff 100644 --- a/gluon/tests/test_validators.py +++ b/gluon/tests/test_validators.py @@ -278,8 +278,68 @@ class TestValidators(unittest.TestCase): self.assertEqual(rtn, ('jerry', 'oops')) rtn = IS_IN_DB(db, 'person.id', '%(name)s', auto_add=True)('jerry') self.assertEqual(rtn, (3, None)) + # Test it works with reference table + db.define_table('ref_table', + Field('name'), + Field('person_id', 'reference person') + ) + ret = db.ref_table.validate_and_insert(name='test reference table') + self.assertFalse(list(ret.errors)) + ret = db.ref_table.validate_and_insert(name='test reference table', person_id=george_id) + self.assertFalse(list(ret.errors)) + rtn = IS_IN_DB(db, 'ref_table.person_id', '%(name)s')(george_id) + self.assertEqual(rtn, (george_id, None)) + # Test it works with reference table.field and keyed table + db.define_table('person_keyed', + Field('name'), + primarykey=['name']) + db.person_keyed.insert(name='george') + db.person_keyed.insert(name='costanza') + rtn = IS_IN_DB(db, 'person_keyed.name')('george') + self.assertEqual(rtn, ('george', None)) + db.define_table('ref_table_field', + Field('name'), + Field('person_name', 'reference person_keyed.name') + ) + ret = db.ref_table_field.validate_and_insert(name='test reference table.field') + self.assertFalse(list(ret.errors)) + ret = db.ref_table_field.validate_and_insert(name='test reference table.field', person_name='george') + self.assertFalse(list(ret.errors)) + vldtr = IS_IN_DB(db, 'ref_table_field.person_name', '%(name)s') + vldtr.options() + rtn = vldtr('george') + self.assertEqual(rtn, ('george', None)) + # Test it works with list:reference table + db.define_table('list_ref_table', + Field('name'), + Field('person_list', 'list:reference person')) + ret = db.list_ref_table.validate_and_insert(name='test list:reference table') + self.assertFalse(list(ret.errors)) + ret = db.list_ref_table.validate_and_insert(name='test list:reference table', person_list=[george_id,costanza_id]) + self.assertFalse(list(ret.errors)) + vldtr = IS_IN_DB(db, 'list_ref_table.person_list') + vldtr.options() + rtn = vldtr([george_id,costanza_id]) + self.assertEqual(rtn, ([george_id,costanza_id], None)) + # Test it works with list:reference table.field and keyed table + #db.define_table('list_ref_table_field', + # Field('name'), + # Field('person_list', 'list:reference person_keyed.name')) + #ret = db.list_ref_table_field.validate_and_insert(name='test list:reference table.field') + #self.assertFalse(list(ret.errors)) + #ret = db.list_ref_table_field.validate_and_insert(name='test list:reference table.field', person_list=['george','costanza']) + #self.assertFalse(list(ret.errors)) + #vldtr = IS_IN_DB(db, 'list_ref_table_field.person_list') + #vldtr.options() + #rtn = vldtr(['george','costanza']) + #self.assertEqual(rtn, (['george','costanza'], None)) db.person.drop() db.category.drop() + db.person_keyed.drop() + db.ref_table.drop() + db.ref_table_field.drop() + db.list_ref_table.drop() + #db.list_ref_table_field.drop() def test_IS_NOT_IN_DB(self): from gluon.dal import DAL, Field