Add support of domain for non-relation field

issue3743
review4181002
This commit is contained in:
Cédric Krier committed 2014-03-15 10:44:45 +01:00
1 parent 64421ff64f
commit a130816cbd
7 files changed
+68 -67

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Add support of domain for non-relation field
* Manage microseconds in JSON-RPC and XML-RPC
* Remove Sha field
* Add password widget
-6
View File
@@ -49,12 +49,6 @@ If ``True``, the field is not editable in the client. Default is ``False``.
A :ref:`domain <topics-domain>` constraint that will be applied on the field
value.
.. warning::
For now it only works on relational fields like :class:`Many2One`,
:class:`One2Many` and :class:`Many2Many`.
..
``states``
----------
+1 -1
View File
@@ -276,6 +276,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
'loading',
'filename',
'selection_change_with',
'domain',
):
if getattr(cls._fields[field], arg, None) is not None:
value = getattr(cls._fields[field], arg)
@@ -352,7 +353,6 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
relation = copy.copy(
cls._fields[field].get_target().__name__)
res[field]['relation'] = relation
res[field]['domain'] = copy.copy(cls._fields[field].domain)
res[field]['context'] = copy.copy(cls._fields[field].context)
res[field]['create'] = accesses.get(field, {}).get('create',
True)
+47 -59
View File
@@ -920,6 +920,51 @@ class ModelStorage(Model):
return True
return False
def validate_domain(field):
if not field.domain:
return
if field._type in ('many2one', 'one2many'):
Relation = pool.get(field.model_name)
elif field._type in ('many2many', 'one2one'):
Relation = field.get_target()
else:
Relation = cls
if is_pyson(field.domain):
pyson_domain = PYSONEncoder().encode(field.domain)
for record in records:
env = EvalEnvironment(record, cls)
env.update(Transaction().context)
env['current_date'] = datetime.datetime.today()
env['time'] = time
env['context'] = Transaction().context
env['active_id'] = record.id
domain = PYSONDecoder(env).decode(pyson_domain)
validate_relation_domain(
field, [record], Relation, domain)
else:
validate_relation_domain(
field, records, Relation, field.domain)
def validate_relation_domain(field, records, Relation, domain):
if Relation != cls:
relations = []
for record in records:
if getattr(record, field.name):
if field._type in ('many2one', 'one2one'):
relations.append(getattr(record, field.name))
else:
relations.extend(getattr(record, field.name))
else:
relations = records
if relations:
finds = Relation.search(['AND',
[('id', 'in', [r.id for r in relations])],
domain,
])
if set(relations) != set(finds):
cls.raise_user_error('domain_validation_record',
error_args=cls._get_error_args(field.name))
field_names = set(field_names or [])
ctx_pref['active_test'] = False
with Transaction().set_context(ctx_pref):
@@ -931,65 +976,8 @@ class ModelStorage(Model):
if isinstance(field, fields.Function) and \
not field.setter:
continue
# validate domain
if (field._type in
('many2one', 'many2many', 'one2many', 'one2one')
and field.domain):
if field._type in ('many2one', 'one2many'):
Relation = pool.get(field.model_name)
else:
Relation = field.get_target()
if is_pyson(field.domain):
pyson_domain = PYSONEncoder().encode(field.domain)
for record in records:
env = EvalEnvironment(record, cls)
env.update(Transaction().context)
env['current_date'] = datetime.datetime.today()
env['time'] = time
env['context'] = Transaction().context
env['active_id'] = record.id
domain = PYSONDecoder(env).decode(pyson_domain)
relation_ids = []
if getattr(record, field_name):
if field._type in ('many2one', 'one2one'):
relation_ids.append(
getattr(record, field_name).id)
else:
relation_ids.extend(
[x.id for x in getattr(record,
field_name)])
if relation_ids and not Relation.search([
'AND',
[('id', 'in', relation_ids)],
domain,
]):
cls.raise_user_error(
'domain_validation_record',
error_args=cls._get_error_args(
field_name))
else:
relation_ids = []
for record in records:
if getattr(record, field_name):
if field._type in ('many2one', 'one2one'):
relation_ids.append(
getattr(record, field_name).id)
else:
relation_ids.extend(
[x.id for x in getattr(record,
field_name)])
if relation_ids:
finds = Relation.search([
'AND',
[('id', 'in', relation_ids)],
field.domain,
])
find_ids = map(int, finds)
if not set(relation_ids) == set(find_ids):
cls.raise_user_error(
'domain_validation_record',
error_args=cls._get_error_args(
field_name))
validate_domain(field)
def required_test(value, field_name):
if (isinstance(value, (type(None), type(False), list,
+1
View File
@@ -22,6 +22,7 @@ def register():
Integer,
IntegerDefault,
IntegerRequired,
IntegerDomain,
Float,
FloatDefault,
FloatRequired,
+7 -1
View File
@@ -8,7 +8,7 @@ from trytond.pyson import Eval
__all__ = [
'Boolean', 'BooleanDefault',
'Integer', 'IntegerDefault', 'IntegerRequired',
'Integer', 'IntegerDefault', 'IntegerRequired', 'IntegerDomain',
'Float', 'FloatDefault', 'FloatRequired', 'FloatDigits',
'Numeric', 'NumericDefault', 'NumericRequired', 'NumericDigits',
'Char', 'CharDefault', 'CharRequired', 'CharSize', 'CharTranslate',
@@ -79,6 +79,12 @@ class IntegerRequired(ModelSQL):
required=True)
class IntegerDomain(ModelSQL):
'Integer Domain'
__name__ = 'test.integer_domain'
integer = fields.Integer('Integer', domain=[('integer', '>', 42)])
class Float(ModelSQL):
'Float'
__name__ = 'test.float'
+11
View File
@@ -29,6 +29,7 @@ class FieldsTestCase(unittest.TestCase):
self.integer = POOL.get('test.integer')
self.integer_default = POOL.get('test.integer_default')
self.integer_required = POOL.get('test.integer_required')
self.integer_domain = POOL.get('test.integer_domain')
self.float = POOL.get('test.float')
self.float_default = POOL.get('test.float_default')
@@ -389,6 +390,16 @@ class FieldsTestCase(unittest.TestCase):
transaction.cursor.rollback()
def test0021integer(self):
'Test Integer with domain'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
self.integer_domain.create([{
'integer': 100,
}])
self.assertRaises(UserError, self.integer_domain.create, [{
'integer': 10,
}])
def test0030float(self):
'Test Float'
with Transaction().start(DB_NAME, USER,