Add Model.__names__ to retrieve model and field names
issue8159 review72431002
This commit is contained in:
1 parent
23a1288d32
commit
10e31bc311
8 files changed
+99
-34
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Add Model.__names__ to retrieve model and field names
|
||||
* Add size attribute on image tag
|
||||
* Allow to use channel to synchronize Cache
|
||||
* Display ids and rule names on access error
|
||||
|
||||
@@ -63,6 +63,12 @@ Class methods:
|
||||
|
||||
Return the definition of each field on the model.
|
||||
|
||||
.. classmethod:: Model.__names__([field])
|
||||
|
||||
Returns a dictionary with the name of the `model` and the `field`.
|
||||
It is a convenience-method used to format messages which should include
|
||||
those names.
|
||||
|
||||
Instance methods:
|
||||
|
||||
.. method:: Model.on_change(fieldnames)
|
||||
|
||||
+38
-4
@@ -66,6 +66,7 @@ class Model(ModelSQL, ModelView):
|
||||
global_search_p = fields.Boolean('Global Search')
|
||||
fields = fields.One2Many('ir.model.field', 'model', 'Fields',
|
||||
required=True)
|
||||
_get_name_cache = Cache('ir.model.get_name')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
@@ -186,6 +187,19 @@ class Model(ModelSQL, ModelView):
|
||||
record.id, name, icon)
|
||||
return heapq.nlargest(int(limit), generate())
|
||||
|
||||
@classmethod
|
||||
def get_name(cls, model):
|
||||
name = cls._get_name_cache.get(model)
|
||||
if name is None:
|
||||
models = cls.search([('model', '=', model)], limit=1)
|
||||
if models:
|
||||
model, = models
|
||||
name = model.name
|
||||
cls._get_name_cache.set(model, name)
|
||||
else:
|
||||
name = model
|
||||
return name
|
||||
|
||||
|
||||
class ModelField(ModelSQL, ModelView):
|
||||
"Model field"
|
||||
@@ -224,6 +238,7 @@ class ModelField(ModelSQL, ModelView):
|
||||
depends=['module'])
|
||||
module = fields.Char('Module',
|
||||
help="Module in which this field is defined")
|
||||
_get_name_cache = Cache('ir.model.field.get_name')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
@@ -333,6 +348,22 @@ class ModelField(ModelSQL, ModelView):
|
||||
('name',) + tuple(clause[1:]),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_name(cls, model, field):
|
||||
name = cls._get_name_cache.get((model, field))
|
||||
if name is None:
|
||||
fields = cls.search([
|
||||
('model.model', '=', model),
|
||||
('name', '=', field),
|
||||
], limit=1)
|
||||
if fields:
|
||||
field, = fields
|
||||
name = field.field_description
|
||||
cls._get_name_cache.set((model, field), name)
|
||||
else:
|
||||
name = field
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def read(cls, ids, fields_names):
|
||||
pool = Pool()
|
||||
@@ -511,6 +542,8 @@ class ModelAccess(DeactivableMixin, ModelSQL, ModelView):
|
||||
@classmethod
|
||||
def check(cls, model_name, mode='read', raise_exception=True):
|
||||
'Check access for model_name and mode'
|
||||
pool = Pool()
|
||||
Model = pool.get(model_name)
|
||||
assert mode in ['read', 'write', 'create', 'delete'], \
|
||||
'Invalid access mode for security'
|
||||
if ((Transaction().user == 0)
|
||||
@@ -522,7 +555,7 @@ class ModelAccess(DeactivableMixin, ModelSQL, ModelView):
|
||||
if not access and access is not None:
|
||||
if raise_exception:
|
||||
raise AccessError(gettext(
|
||||
'ir.msg_access_rule_error', model=model_name))
|
||||
'ir.msg_access_rule_error', **Model.__names__()))
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
@@ -557,7 +590,7 @@ class ModelAccess(DeactivableMixin, ModelSQL, ModelView):
|
||||
# XXX Can not check access right on instance method
|
||||
selection = []
|
||||
for model_name, _ in selection:
|
||||
if not cls.check(model_name, mode=mode,
|
||||
if model_name and not cls.check(model_name, mode=mode,
|
||||
raise_exception=False):
|
||||
return False
|
||||
return True
|
||||
@@ -692,6 +725,8 @@ class ModelFieldAccess(DeactivableMixin, ModelSQL, ModelView):
|
||||
'''
|
||||
Check access for fields on model_name.
|
||||
'''
|
||||
pool = Pool()
|
||||
Model = pool.get(model_name)
|
||||
assert mode in ('read', 'write', 'create', 'delete'), \
|
||||
'Invalid access mode'
|
||||
if ((Transaction().user == 0)
|
||||
@@ -710,8 +745,7 @@ class ModelFieldAccess(DeactivableMixin, ModelSQL, ModelView):
|
||||
if raise_exception:
|
||||
raise AccessError(
|
||||
gettext('ir.msg_access_rule_field_error',
|
||||
model=model_name,
|
||||
field=field))
|
||||
**Model.__names__(field)))
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -621,7 +621,11 @@ class Translation(ModelSQL, ModelView):
|
||||
def delete(cls, translations):
|
||||
pool = Pool()
|
||||
Message = pool.get('ir.message')
|
||||
Model = pool.get('ir.model')
|
||||
ModelField = pool.get('ir.model.field')
|
||||
Message._message_cache.clear()
|
||||
Model._get_name_cache.clear()
|
||||
ModelField._get_name_cache.clear()
|
||||
cls._translation_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
return super(Translation, cls).delete(translations)
|
||||
@@ -630,7 +634,11 @@ class Translation(ModelSQL, ModelView):
|
||||
def create(cls, vlist):
|
||||
pool = Pool()
|
||||
Message = pool.get('ir.message')
|
||||
Model = pool.get('ir.model')
|
||||
ModelField = pool.get('ir.model.field')
|
||||
Message._message_cache.clear()
|
||||
Model._get_name_cache.clear()
|
||||
ModelField._get_name_cache.clear()
|
||||
cls._translation_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
vlist = [x.copy() for x in vlist]
|
||||
@@ -645,7 +653,11 @@ class Translation(ModelSQL, ModelView):
|
||||
def write(cls, *args):
|
||||
pool = Pool()
|
||||
Message = pool.get('ir.message')
|
||||
Model = pool.get('ir.model')
|
||||
ModelField = pool.get('ir.model.field')
|
||||
Message._message_cache.clear()
|
||||
Model._get_name_cache.clear()
|
||||
ModelField._get_name_cache.clear()
|
||||
cls._translation_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
return super(Translation, cls).write(*args)
|
||||
|
||||
@@ -203,6 +203,19 @@ class Model(URLMixin, PoolBase, metaclass=ModelMeta):
|
||||
def pre_validate(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def __names__(cls, field=None):
|
||||
pool = Pool()
|
||||
IrModel = pool.get('ir.model')
|
||||
IrModelField = pool.get('ir.model.field')
|
||||
|
||||
names = {
|
||||
'model': IrModel.get_name(cls.__name__),
|
||||
}
|
||||
if field:
|
||||
names['field'] = IrModelField.get_name(cls.__name__, field)
|
||||
return names
|
||||
|
||||
def __init__(self, id=None, **kwargs):
|
||||
super(Model, self).__init__()
|
||||
if id is not None:
|
||||
|
||||
@@ -352,7 +352,7 @@ class ModelSQL(ModelStorage):
|
||||
if values.get(field_name) is None:
|
||||
raise RequiredValidationError(
|
||||
gettext('ir.msg_required_validation_record',
|
||||
**cls._get_error_args(field_name)))
|
||||
**cls.__names__(field_name)))
|
||||
for name, _, error in cls._sql_constraints:
|
||||
if TableHandler.convert_name(name) in str(exception):
|
||||
raise SQLConstraintError(gettext(error))
|
||||
@@ -374,7 +374,7 @@ class ModelSQL(ModelStorage):
|
||||
if not ((target_records
|
||||
or (values[field_name] in create_records))
|
||||
and (values[field_name] not in delete_records)):
|
||||
error_args = cls._get_error_args(field_name)
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['value'] = values[field_name]
|
||||
raise ForeignKeyError(
|
||||
gettext('ir.msg_foreign_model_missing',
|
||||
@@ -1114,7 +1114,7 @@ class ModelSQL(ModelStorage):
|
||||
if Model.search([
|
||||
(field_name, 'in', sub_ids),
|
||||
], order=[]):
|
||||
error_args = Model._get_error_args(field_name)
|
||||
error_args = Model.__names__(field_name)
|
||||
raise ForeignKeyError(
|
||||
gettext('ir.msg_foreign_model_exist',
|
||||
**error_args))
|
||||
|
||||
@@ -928,27 +928,6 @@ class ModelStorage(Model):
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _get_error_args(cls, field_name):
|
||||
pool = Pool()
|
||||
ModelField = pool.get('ir.model.field')
|
||||
error_args = {
|
||||
'field': field_name,
|
||||
'model': cls.__name__
|
||||
}
|
||||
if ModelField:
|
||||
model_fields = ModelField.search([
|
||||
('name', '=', field_name),
|
||||
('model.model', '=', cls.__name__),
|
||||
], limit=1)
|
||||
if model_fields:
|
||||
model_field, = model_fields
|
||||
error_args.update({
|
||||
'field': model_field.field_description,
|
||||
'model': model_field.model.name,
|
||||
})
|
||||
return error_args
|
||||
|
||||
@classmethod
|
||||
def validate(cls, records):
|
||||
pass
|
||||
@@ -1067,7 +1046,7 @@ class ModelStorage(Model):
|
||||
if sub_relations != set(finds):
|
||||
raise DomainValidationError(
|
||||
gettext('ir.msg_domain_validation_record',
|
||||
**cls._get_error_args(field.name)))
|
||||
**cls.__names__(field.name)))
|
||||
|
||||
field_names = set(field_names or [])
|
||||
function_fields = {name for name, field in cls._fields.items()
|
||||
@@ -1094,7 +1073,7 @@ class ModelStorage(Model):
|
||||
and not isinstance(value, ModelStorage))):
|
||||
raise RequiredValidationError(
|
||||
gettext('ir.msg_required_validation_record',
|
||||
**cls._get_error_args(field_name)))
|
||||
**cls.__names__(field_name)))
|
||||
# validate states required
|
||||
if field.states and 'required' in field.states:
|
||||
if is_pyson(field.states['required']):
|
||||
@@ -1137,7 +1116,7 @@ class ModelStorage(Model):
|
||||
field_size = field.size
|
||||
size = len(getattr(record, field_name) or '')
|
||||
if (size > field_size >= 0):
|
||||
error_args = cls._get_error_args(field_name)
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['size'] = size
|
||||
error_args['max_size'] = field_size
|
||||
raise SizeValidationError(
|
||||
@@ -1146,7 +1125,7 @@ class ModelStorage(Model):
|
||||
|
||||
def digits_test(value, digits, field_name):
|
||||
def raise_error(value):
|
||||
error_args = cls._get_error_args(field_name)
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['digits'] = digits[1]
|
||||
error_args['value'] = repr(value)
|
||||
raise DigitsValidationError(
|
||||
@@ -1205,7 +1184,7 @@ class ModelStorage(Model):
|
||||
test.add('')
|
||||
test.add(None)
|
||||
if value not in test:
|
||||
error_args = cls._get_error_args(field_name)
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['value'] = value
|
||||
raise SelectionValidationError(
|
||||
gettext('ir.msg_selection_validation_record',
|
||||
@@ -1218,7 +1197,7 @@ class ModelStorage(Model):
|
||||
value = value.time()
|
||||
if value != datetime.datetime.strptime(
|
||||
value.strftime(format), format).time():
|
||||
error_args = cls._get_error_args(field_name)
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['value'] = value
|
||||
raise TimeFormatValidationError(
|
||||
gettext('ir.msg_time_format_validation_record',
|
||||
|
||||
@@ -56,6 +56,26 @@ class ModelTestCase(unittest.TestCase):
|
||||
self.assertEqual(record.parent.name, "Test 1")
|
||||
self.assertEqual(record.parent.parent.name, "Test 2")
|
||||
|
||||
@with_transaction()
|
||||
def test_names_model(self):
|
||||
"Test __names__ for model only"
|
||||
pool = Pool()
|
||||
Model = pool.get('test.model')
|
||||
|
||||
names = Model.__names__()
|
||||
|
||||
self.assertEqual(names, {'model': "Model"})
|
||||
|
||||
@with_transaction()
|
||||
def test_names_field(self):
|
||||
"Test __names__ with field"
|
||||
pool = Pool()
|
||||
Model = pool.get('test.model')
|
||||
|
||||
names = Model.__names__('name')
|
||||
|
||||
self.assertEqual(names, {'model': "Model", 'field': "Name"})
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromTestCase(ModelTestCase)
|
||||
Reference in new issue
Block a user