New interface for Function/Property fields

Function field takes an other field in parameters
set/get function on Fields take a list of ids
This commit is contained in:
Cédric Krier
2010-03-11 16:42:50 +01:00
parent 8951e54c86
commit dd6918994f
18 changed files with 243 additions and 312 deletions
+4
View File
@@ -1,3 +1,7 @@
* set/get function on Fields take a list of ids
* New interface for Function/Property fields
Take a Field as first argument instead of many separate arguments
Remove static arguments
* Fix Float and Numeric for lost of precision
* Add decimal digits validation on fields
* Improve unittests to run trytond from tests
-20
View File
@@ -549,26 +549,6 @@ The framework is able to check, if ``names`` (instead of ``name``) is used in
the method definition, hence adapting the way the method is called.
Another way to tackle Function implementation is to pass a dictionary to the
``args`` argument on the field definition. It will be forwarded to the function
call:
.. highlight:: python
::
state = fields.Function(
'get_state', type='selection', string='Total Service',
args={'key':'value'},
selection=[('draft','Draft'),('done','Done')],
)
def get_state(self, cursor, user, ids, names, arg, context=None):
# [...]
if arg.get('key'):
pass # do something with 'value'
Search on Function fields
+++++++++++++++++++++++++
+19 -21
View File
@@ -216,15 +216,14 @@ class ActionReport(ModelSQL, ModelView):
report_name = fields.Char('Internal Name', required=True)
report = fields.Char('Path')
report_content_data = fields.Binary('Content')
report_content = fields.Function('get_report_content',
fnct_inv='report_content_inv', type='binary',
string='Content')
report_content = fields.Function(fields.Binary('Content'),
'get_report_content', setter='set_report_content')
action = fields.Many2One('ir.action', 'Action', required=True,
ondelete='CASCADE')
style = fields.Property(type='char', string='Style',
help='Define the style to apply on the report.')
style_content = fields.Function('get_style_content',
type='binary', string='Style')
style = fields.Property(fields.Char('Style',
help='Define the style to apply on the report.'))
style_content = fields.Function(fields.Binary('Style'),
'get_style_content')
direct_print = fields.Boolean('Direct Print')
extension = fields.Selection(
[('odt', 'ODT Document'),
@@ -281,7 +280,7 @@ class ActionReport(ModelSQL, ModelView):
def default_module(self, cursor, user, context=None):
return context and context.get('module', '') or ''
def get_report_content(self, cursor, user, ids, name, arg, context=None):
def get_report_content(self, cursor, user, ids, name, context=None):
res = {}
for report in self.browse(cursor, user, ids, context=context):
data = report[name + '_data']
@@ -295,11 +294,12 @@ class ActionReport(ModelSQL, ModelView):
res[report.id] = data
return res
def report_content_inv(self, cursor, user, obj_id, name, value, arg,
def set_report_content(self, cursor, user, ids, name, value,
context=None):
self.write(cursor, user, obj_id, {name+'_data': value}, context=context)
self.write(cursor, user, ids, {'%s_data' % name: value},
context=context)
def get_style_content(self, cursor, user, ids, name, arg, context=None):
def get_style_content(self, cursor, user, ids, name, context=None):
res = {}
for report in self.browse(cursor, user, ids, context=context):
try:
@@ -396,8 +396,7 @@ class ActionActWindow(ModelSQL, ModelView):
], string='Type of view')
act_window_views = fields.One2Many('ir.action.act_window.view',
'act_window', 'Views')
views = fields.Function('views_get_fnc', type='binary',
string='Views')
views = fields.Function(fields.Binary('Views'), 'get_views')
limit = fields.Integer('Limit',
help='Default limit for the list view')
auto_refresh = fields.Integer('Auto-Refresh',
@@ -408,12 +407,11 @@ class ActionActWindow(ModelSQL, ModelView):
help='Use the action name as window name')
search_value = fields.Char('Search Criteria',
help='Default search criteria for the list view')
pyson_domain = fields.Function('get_pyson', type='string',
string='PySON Domain')
pyson_context = fields.Function('get_pyson', type='string',
string='PySON Context')
pyson_search_value = fields.Function('get_pyson', type='string',
string='PySON Search Criteria')
pyson_domain = fields.Function(fields.Char('PySON Domain'), 'get_pyson')
pyson_context = fields.Function(fields.Char('PySON Context'),
'get_pyson')
pyson_search_value = fields.Function(fields.Char(
'PySON Search Criteria'), 'get_pyson')
def __init__(self):
super(ActionActWindow, self).__init__()
@@ -504,14 +502,14 @@ class ActionActWindow(ModelSQL, ModelView):
return False
return True
def views_get_fnc(self, cursor, user, ids, name, arg, context=None):
def get_views(self, cursor, user, ids, name, context=None):
res = {}
for act in self.browse(cursor, user, ids, context=context):
res[act.id] = [(view.view.id, view.view.type) \
for view in act.act_window_views]
return res
def get_pyson(self, cursor, user, ids, name, arg, context=None):
def get_pyson(self, cursor, user, ids, name, context=None):
res = {}
encoder = PYSONEncoder()
field = name[6:]
+9 -10
View File
@@ -16,16 +16,15 @@ class Attachment(ModelSQL, ModelView):
_name = 'ir.attachment'
_description = __doc__
name = fields.Char('Attachment Name', required=True)
datas = fields.Function('get_datas', fnct_inv='set_datas',
type='binary', string='Datas')
datas = fields.Function(fields.Binary('Datas'), 'get_datas',
setter='set_datas')
description = fields.Text('Description')
res_model = fields.Char('Resource Model', readonly=True)
res_id = fields.Integer('Resource ID', readonly=True)
link = fields.Char('Link')
digest = fields.Char('Digest', size=32)
collision = fields.Integer('Collision')
datas_size = fields.Function('get_datas', type='integer',
string='Datas size')
datas_size = fields.Function(fields.Integer('Datas size'), 'get_datas')
def __init__(self):
super(Attachment, self).__init__()
@@ -38,7 +37,7 @@ class Attachment(ModelSQL, ModelView):
def default_collision(self, cursor, user, context=None):
return 0
def get_datas(self, cursor, user, ids, name, arg, context=None):
def get_datas(self, cursor, user, ids, name, context=None):
res = {}
db_name = cursor.dbname
for attachment in self.browse(cursor, user, ids, context=context):
@@ -64,7 +63,7 @@ class Attachment(ModelSQL, ModelView):
res[attachment.id] = value
return res
def set_datas(self, cursor, user, obj_id, name, value, args, context=None):
def set_datas(self, cursor, user, ids, name, value, context=None):
if value is False or value is None:
return
db_name = cursor.dbname
@@ -113,10 +112,10 @@ class Attachment(ModelSQL, ModelView):
file_p = open(filename, 'wb')
file_p.write(data)
file_p.close()
cursor.execute('UPDATE ir_attachment ' \
'SET digest = %s, ' \
'collision = %s ' \
'WHERE id = %s', (digest, collision, obj_id))
self.write(cursor, user, ids, {
'digest': digest,
'collision': collision,
}, context=context)
def check_access(self, cursor, user, ids, mode='read', context=None):
model_access_obj = self.pool.get('ir.model.access')
+11 -13
View File
@@ -133,7 +133,7 @@ class Module(ModelSQL, ModelView):
description = fields.Text("Description", readonly=True, translate=True)
author = fields.Char("Author", readonly=True)
website = fields.Char("Website", readonly=True)
version = fields.Function('get_version', string='Version', type='char')
version = fields.Function(fields.Char('Version'), 'get_version')
dependencies = fields.One2Many('ir.module.module.dependency',
'module', 'Dependencies', readonly=True)
state = fields.Selection([
@@ -186,8 +186,7 @@ class Module(ModelSQL, ModelView):
return {}
return info
def get_version(self, cursor, user, ids, name, arg,
context=None):
def get_version(self, cursor, user, ids, name, context=None):
res = {}
for module in self.browse(cursor, user, ids, context=context):
res[module.id] = Module.get_module_info(
@@ -465,15 +464,14 @@ class ModuleDependency(ModelSQL, ModelView):
name = fields.Char('Name')
module = fields.Many2One('ir.module.module', 'Module', select=1,
ondelete='CASCADE', required=True)
state = fields.Function('get_state', type='selection',
selection=[
('uninstalled','Not Installed'),
('installed','Installed'),
('to upgrade','To be upgraded'),
('to remove','To be removed'),
('to install','To be installed'),
('unknown', 'Unknown'),
], string='State', readonly=True)
state = fields.Function(fields.Selection([
('uninstalled','Not Installed'),
('installed','Installed'),
('to upgrade','To be upgraded'),
('to remove','To be removed'),
('to install','To be installed'),
('unknown', 'Unknown'),
], 'State', readonly=True), 'get_state')
def __init__(self):
super(ModuleDependency, self).__init__()
@@ -482,7 +480,7 @@ class ModuleDependency(ModelSQL, ModelView):
'Dependency must be unique by module!'),
]
def get_state(self, cursor, user, ids, name, args, context=None):
def get_state(self, cursor, user, ids, name, context=None):
result = {}
module_obj = self.pool.get('ir.module.module')
for dependency in self.browse(cursor, user, ids):
+8 -7
View File
@@ -147,14 +147,14 @@ class Property(ModelSQL, ModelView):
'field': field_id,
}
def set(self, cursor, user, name, model, res_id, val, context=None):
def set(self, cursor, user, name, model, ids, val, context=None):
"""
Set property value for res_id
Set property value for ids
:param cursor: the database cursor
:param user: the user id
:param names: property name
:param model: object name
:param res_id: a record ids
:param ids: a list of ids
:param val: the value
:param context: the context
:return: the id of the record created
@@ -177,7 +177,7 @@ class Property(ModelSQL, ModelView):
property_ids = self.search(cursor, user, [
('field', '=', field_id),
('res', '=', model + ',' + str(res_id)),
('res', 'in', [model + ',' + str(res_id) for res_id in ids]),
], order=[], context=context)
self.delete(cursor, 0, property_ids, context=ctx)
@@ -208,9 +208,10 @@ class Property(ModelSQL, ModelView):
res = False
if (val != default_val):
vals = self._set_values(cursor, user, name, model, res_id, val,
field_id, context=context)
res = self.create(cursor, 0, vals, context=ctx)
for res_id in ids:
vals = self._set_values(cursor, user, name, model, res_id, val,
field_id, context=context)
res = self.create(cursor, 0, vals, context=ctx)
return res
Property()
+4 -4
View File
@@ -53,8 +53,8 @@ class Translation(ModelSQL, ModelView, Cacheable):
value = fields.Text('Translation Value')
module = fields.Char('Module', readonly=True)
fuzzy = fields.Boolean('Fuzzy')
model = fields.Function('get_model', fnct_search='model_search',
type='char', string='Model')
model = fields.Function(fields.Char('Model'), 'get_model',
searcher='search_model')
def __init__(self):
super(Translation, self).__init__()
@@ -75,13 +75,13 @@ class Translation(ModelSQL, ModelView, Cacheable):
def default_fuzzy(self, cursor, user, context=None):
return False
def get_model(self, cursor, user, ids, name, arg, context=None):
def get_model(self, cursor, user, ids, name, context=None):
res = {}
for translation in self.browse(cursor, user, ids, context=context):
res[translation.id] = translation.name.split(',')[0]
return res
def model_search(self, cursor, user, name, args, context=None):
def search_model(self, cursor, user, name, args, context=None):
args2 = []
i = 0
while i < len(args):
+26 -23
View File
@@ -82,17 +82,16 @@ class UIMenu(ModelSQL, ModelView):
parent = fields.Many2One('ir.ui.menu', 'Parent Menu', select=1)
groups = fields.Many2Many('ir.ui.menu-res.group',
'menu_id', 'gid', 'Groups')
complete_name = fields.Function('get_full_name',
string='Complete Name', type='char', order_field='name')
complete_name = fields.Function(fields.Char('Complete Name',
order_field='name'), 'get_full_name')
icon = fields.Selection(ICONS, 'Icon', translate=False)
action = fields.Function('get_action', fnct_inv='action_inv',
type='reference', string='Action',
selection=[
('ir.action.report', 'ir.action.report'),
('ir.action.act_window', 'ir.action.act_window'),
('ir.action.wizard', 'ir.action.wizard'),
('ir.action.url', 'ir.action.url'),
])
action = fields.Function(fields.Reference('Action',
selection=[
('ir.action.report', 'ir.action.report'),
('ir.action.act_window', 'ir.action.act_window'),
('ir.action.wizard', 'ir.action.wizard'),
('ir.action.url', 'ir.action.url'),
]), 'get_action', setter='set_action')
active = fields.Boolean('Active')
def __init__(self):
@@ -108,7 +107,7 @@ class UIMenu(ModelSQL, ModelView):
def default_active(self, cursor, user, context=None):
return True
def get_full_name(self, cursor, user, ids, name, args, context):
def get_full_name(self, cursor, user, ids, name, context):
res = {}
for menu in self.browse(cursor, user, ids, context=context):
res[menu.id] = self._get_one_full_name(menu)
@@ -146,7 +145,7 @@ class UIMenu(ModelSQL, ModelView):
res = check_menu(res)
return res
def get_action(self, cursor, user, ids, name, arg, context=None):
def get_action(self, cursor, user, ids, name, context=None):
action_keyword_obj = self.pool.get('ir.action.keyword')
if context is None:
@@ -176,8 +175,7 @@ class UIMenu(ModelSQL, ModelView):
res[model_id] = action_keyword.action.type + ',' + str(action_id)
return res
def action_inv(self, cursor, user, menu_id, name, value, arg,
context=None):
def set_action(self, cursor, user, ids, name, value, context=None):
if context is None:
context = {}
if not value:
@@ -186,10 +184,14 @@ class UIMenu(ModelSQL, ModelView):
if '_timestamp' in ctx:
del ctx['_timestamp']
action_keyword_obj = self.pool.get('ir.action.keyword')
action_keyword_ids = action_keyword_obj.search(cursor, user, [
('keyword', '=', 'tree_open'),
('model', '=', self._name + ',' + str(menu_id)),
], context=context)
action_keyword_ids = []
for i in range(0, len(ids), cursor.IN_MAX):
sub_ids = ids[i:i + cursor.IN_MAX]
action_keyword_ids += action_keyword_obj.search(cursor, user, [
('keyword', '=', 'tree_open'),
('model', 'in', [self._name + ',' + str(menu_id)
for menu_id in sub_ids]),
], context=context)
if action_keyword_ids:
action_keyword_obj.delete(cursor, user, action_keyword_ids,
context=ctx)
@@ -199,10 +201,11 @@ class UIMenu(ModelSQL, ModelView):
action_obj = self.pool.get(action_type)
action = action_obj.browse(cursor, user, int(action_id),
context=context)
action_keyword_obj.create(cursor, user, {
'keyword': 'tree_open',
'model': self._name + ',' + str(menu_id),
'action': action.action.id,
}, context=ctx)
for menu_id in ids:
action_keyword_obj.create(cursor, user, {
'keyword': 'tree_open',
'model': self._name + ',' + str(menu_id),
'action': action.action.id,
}, context=ctx)
UIMenu()
+43 -81
View File
@@ -1,93 +1,55 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import inspect
import copy
from trytond.model.fields.field import Field
from trytond.model.fields.float import digits_validate
from trytond.model.fields.one2many import add_remove_validate
from trytond.pyson import PYSON
import inspect
class Function(Field):
'''
Define function field (any).
'''
_type = 'float'
def __init__(self, fnct, arg=None, fnct_inv='', fnct_inv_arg=None,
type='float', fnct_search='', model_name=None, selection=None,
digits=None, relation=None, add_remove=None, datetime_field=None,
string='', help='', required=False, readonly=False, domain=None,
states=None, priority=0, change_default=False, translate=False,
select=0, on_change=None, on_change_with=None, depends=None,
order_field=None, context=None):
def __init__(self, field, getter, setter=None, searcher=None):
'''
:param fnct: The name of the function.
:param arg: Argument for the function.
:param fnct_inv: The name of the function to write.
:param fnct_inv_arg: Argument for the function to write.
:param type: The type of field.
:param fnct_search: The name of the function to search.
:param model_name: See Many2One.
:param selection: See Selection.
:param digits: See Float.
:param relation: Like model_name.
:param add_remove: See Many2One.
:param datetime_field: The name of the field that contains the datetime
value to read the target records.
:param field: The field of the function.
:param getter: The name of the function for getting values.
:param setter: The name of the function to set value.
:param searcher: The name of the function to search.
'''
if datetime_field:
if depends:
depends.append(datetime_field)
else:
depends = [datetime_field]
super(Function, self).__init__(string=string, help=help,
required=required, readonly=readonly, domain=domain,
states=states, priority=priority, change_default=change_default,
translate=translate, select=select, on_change=on_change,
on_change_with=on_change_with, depends=depends,
order_field=order_field, context=context)
self.model_name = model_name
self.fnct = fnct
self.arg = arg
self.fnct_inv = fnct_inv
self.fnct_inv_arg = fnct_inv_arg
if not self.fnct_inv:
self.readonly = True
self._type = type
self.fnct_search = fnct_search
self.selection = selection
self.__digits = None
self.digits = digits
if relation:
self.model_name = relation
self.__add_remove = None
self.add_remove = add_remove
self.datetime_field = datetime_field
assert isinstance(field, Field)
self._field = field
self._type = field._type
self.getter = getter
self.setter = setter
if not self.setter:
self._field.readonly = True
self.searcher = searcher
__init__.__doc__ += Field.__init__.__doc__
def _get_digits(self):
return self.__digits
def __copy__(self):
return Function(copy.copy(self._field), self.getter,
setter=self.setter, searcher=self.searcher)
def _set_digits(self, value):
digits_validate(value)
self.__digits = value
def __getattr__(self, name):
return getattr(self._field, name)
digits = property(_get_digits, _set_digits)
def __getitem__(self, name):
return self._field[name]
def _get_add_remove(self):
return self.__add_remove
def _set_add_remove(self, value):
add_remove_validate(value)
self.__add_remove = value
add_remove = property(_get_add_remove, _set_add_remove)
def __setattr__(self, name, value):
if name in ('_field', '_type', 'getter', 'setter', 'searcher'):
return object.__setattr__(self, name, value)
return setattr(self._field, name, value)
def search(self, cursor, user, model, name, args, context=None):
'''
Call the fnct_search.
Call the searcher.
:param cursor: The database cursor.
:param user: The user id.
@@ -97,15 +59,15 @@ class Function(Field):
:param context: The context.
:return: New list of domain.
'''
if not self.fnct_search:
if not self.searcher:
model.raise_user_error(cursor, 'search_function_missing',
name, context=context)
return getattr(model, self.fnct_search)(cursor, user, name, args,
return getattr(model, self.searcher)(cursor, user, name, args,
context=context)
def get(self, cursor, user, ids, model, name, values=None, context=None):
'''
Call the fnct.
Call the getter.
If the function has ``names`` in the function definition then
it will call it with a list of name.
@@ -123,34 +85,34 @@ class Function(Field):
if isinstance(name, list):
names = name
# Test is the function works with a list of names
if 'names' in inspect.getargspec(getattr(model, self.fnct))[0]:
return getattr(model, self.fnct)(cursor, user, ids, names,
self.arg, context=context)
if 'names' in inspect.getargspec(getattr(model, self.getter))[0]:
return getattr(model, self.getter)(cursor, user, ids, names,
context=context)
res = {}
for name in names:
res[name] = getattr(model, self.fnct)(cursor, user, ids, name,
self.arg, context=context)
res[name] = getattr(model, self.getter)(cursor, user, ids,
name, context=context)
return res
else:
# Test is the function works with a list of names
if 'names' in inspect.getargspec(getattr(model, self.fnct))[0]:
if 'names' in inspect.getargspec(getattr(model, self.getter))[0]:
name = [name]
return getattr(model, self.fnct)(cursor, user, ids, name, self.arg,
return getattr(model, self.getter)(cursor, user, ids, name,
context=context)
def set(self, cursor, user, record_id, model, name, value, context=None):
def set(self, cursor, user, ids, model, name, value, context=None):
'''
Call the fnct_inv.
Call the setter.
:param cursor: The database cursor.
:param user: The user id.
:param record_id: The record id.
:param ids: A list of ids.
:param model: The model.
:param name: The name of the field.
:param value: The value to set.
:param context: The context.
'''
if self.fnct_inv:
getattr(model, self.fnct_inv)(cursor, user, record_id, name, value,
self.fnct_inv_arg, context=context)
if self.setter:
getattr(model, self.setter)(cursor, user, ids, name, value,
context=context)
+40 -38
View File
@@ -82,13 +82,13 @@ class Many2Many(Field):
res[relation[self.origin]].append(relation[self.target])
return res
def set(self, cursor, user, record_id, model, name, values, context=None):
def set(self, cursor, user, ids, model, name, values, context=None):
'''
Set the values.
:param cursor: The database cursor
:param user: The user id
:param record_id: The record id
:param ids: A list of ids
:param model: A string with the name of the model
:param name: A string with the name of the field
:param values: A list of tuples:
@@ -107,75 +107,77 @@ class Many2Many(Field):
target_obj = self.get_target(model.pool)
for act in values:
if act[0] == 'create':
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: target_obj.create(cursor, user, act[1],
context=context),
}, context=context)
for record_id in ids:
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: target_obj.create(cursor, user, act[1],
context=context),
}, context=context)
elif act[0] == 'write':
target_obj.write(cursor, user, act[1] , act[2], context=context)
elif act[0] == 'delete':
target_obj.delete(cursor, user, act[1], context=context)
elif act[0] == 'unlink':
if isinstance(act[1], (int, long)):
ids = [act[1]]
target_ids = [act[1]]
else:
ids = list(act[1])
if not ids:
target_ids = list(act[1])
if not target_ids:
continue
relation_ids = []
for i in range(0, len(ids), cursor.IN_MAX):
sub_ids = ids[i:i + cursor.IN_MAX]
for i in range(0, len(target_ids), cursor.IN_MAX):
sub_ids = target_ids[i:i + cursor.IN_MAX]
relation_ids += relation_obj.search(cursor, user, [
(self.origin, '=', record_id),
(self.origin, 'in', ids),
(self.target, 'in', sub_ids),
], context=context)
relation_obj.delete(cursor, user, relation_ids, context=context)
elif act[0] == 'add':
if isinstance(act[1], (int, long)):
ids = [act[1]]
target_ids = [act[1]]
else:
ids = list(act[1])
if not ids:
target_ids = list(act[1])
if not target_ids:
continue
existing_ids = []
for i in range(0, len(ids), cursor.IN_MAX):
sub_ids = ids[i:i + cursor.IN_MAX]
for i in range(0, len(target_ids), cursor.IN_MAX):
sub_ids = target_ids[i:i + cursor.IN_MAX]
relation_ids = relation_obj.search(cursor, user, [
(self.origin, '=', record_id),
(self.origin, 'in', ids),
(self.target, 'in', sub_ids),
], context=context)
for relation in relation_obj.browse(cursor, user,
relation_ids, context=context):
existing_ids.append(relation[self.target].id)
new_ids = [x for x in ids if x not in existing_ids]
for new_id in new_ids:
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: new_id,
}, context=context)
for new_id in (x for x in target_ids if x not in existing_ids):
for record_id in ids:
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: new_id,
}, context=context)
elif act[0] == 'unlink_all':
ids = relation_obj.search(cursor, user, [
(self.origin, '=', record_id),
target_ids = relation_obj.search(cursor, user, [
(self.origin, 'in', ids),
(self.target + '.id', '!=', False),
], context=context)
relation_obj.delete(cursor, user, ids, context=context)
relation_obj.delete(cursor, user, target_ids, context=context)
elif act[0] == 'set':
if not act[1]:
ids = []
target_ids = []
else:
ids = list(act[1])
ids2 = relation_obj.search(cursor, user, [
(self.origin, '=', record_id),
target_ids = list(act[1])
target_ids2 = relation_obj.search(cursor, user, [
(self.origin, 'in', ids),
(self.target + '.id', '!=', False),
], context=context)
relation_obj.delete(cursor, user, ids2, context=context)
relation_obj.delete(cursor, user, target_ids2, context=context)
for new_id in ids:
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: new_id,
}, context=context)
for new_id in target_ids:
for record_id in ids:
relation_obj.create(cursor, user, {
self.origin: record_id,
self.target: new_id,
}, context=context)
else:
raise Exception('Bad arguments')
+38 -36
View File
@@ -106,13 +106,13 @@ class One2Many(Field):
val.sort(lambda x, y: cmp(index_of_ids2[x], index_of_ids2[y]))
return res
def set(self, cursor, user, record_id, model, name, values, context=None):
def set(self, cursor, user, ids, model, name, values, context=None):
'''
Set the values.
:param cursor: The database cursor
:param user: The user id
:param record_id: The record id
:param ids: A list of ids
:param model: A string with the name of the model
:param name: A string with the name of the field
:param values: A list of tuples:
@@ -131,64 +131,66 @@ class One2Many(Field):
model = model.pool.get(self.model_name)
for act in values:
if act[0] == 'create':
act[1][self.field] = record_id
model.create(cursor, user, act[1], context=context)
for record_id in ids:
act[1][self.field] = record_id
model.create(cursor, user, act[1], context=context)
elif act[0] == 'write':
act[2][self.field] = record_id
model.write(cursor, user, act[1] , act[2], context=context)
elif act[0] == 'delete':
model.delete(cursor, user, act[1], context=context)
elif act[0] == 'delete_all':
ids = model.search(cursor, user, [
(self.field, '=', record_id),
target_ids = model.search(cursor, user, [
(self.field, 'in', ids),
], context=context)
model.delete(cursor, user, ids, context=context)
model.delete(cursor, user, target_ids, context=context)
elif act[0] == 'unlink':
if isinstance(act[1], (int, long)):
ids = [act[1]]
target_ids = [act[1]]
else:
ids = list(act[1])
if not ids:
target_ids = list(act[1])
if not target_ids:
continue
ids = model.search(cursor, user, [
(self.field, '=', record_id),
('id', 'in', ids),
target_ids = model.search(cursor, user, [
(self.field, 'in', ids),
('id', 'in', target_ids),
], context=context)
model.write(cursor, user, ids, {
model.write(cursor, user, target_ids, {
self.field: False,
}, context=context)
elif act[0] == 'add':
if isinstance(act[1], (int, long)):
ids = [act[1]]
target_ids = [act[1]]
else:
ids = list(act[1])
if not ids:
target_ids = list(act[1])
if not target_ids:
continue
ids = model.write(cursor, user, ids, {
self.field: record_id,
}, context=context)
for record_id in ids:
model.write(cursor, user, target_ids, {
self.field: record_id,
}, context=context)
elif act[0] == 'unlink_all':
ids = model.search(cursor, user, [
(self.field, '=', record_id),
target_ids = model.search(cursor, user, [
(self.field, 'in', ids),
], context=context)
model.write(cursor, user, ids, {
model.write(cursor, user, target_ids, {
self.field: False,
}, context=context)
elif act[0] == 'set':
if not act[1]:
ids = [0]
target_ids = [0]
else:
ids = list(act[1])
ids2 = model.search(cursor, user, [
(self.field, '=', record_id),
('id', 'not in', ids),
], context=context)
model.write(cursor, user, ids2, {
self.field: False,
}, context=context)
if act[1]:
model.write(cursor, user, ids, {
self.field: record_id,
target_ids = list(act[1])
for record_id in ids:
target_ids2 = model.search(cursor, user, [
(self.field, '=', record_id),
('id', 'not in', target_ids),
], context=context)
model.write(cursor, user, target_ids2, {
self.field: False,
}, context=context)
if act[1]:
model.write(cursor, user, target_ids, {
self.field: record_id,
}, context=context)
else:
raise Exception('Bad arguments')
+12 -26
View File
@@ -1,6 +1,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import copy
from trytond.model.fields.function import Function
from trytond.model.fields.field import Field
from trytond import backend
@@ -11,32 +12,17 @@ class Property(Function):
Define a property field that is stored in ir.property (any).
'''
def __init__(self, type='float', model_name=None, selection=None,
digits=None, relation=None, add_remove=None, string='', help='',
required=False, readonly=False, domain=None, states=None,
priority=0, change_default=False, translate=False, select=0,
on_change=None, on_change_with=None, depends=None,
order_field=None, context=None):
def __init__(self, field):
'''
:param type: The type of the field.
:param fnct_search: The name of the search function.
:param model_name: See Many2One.
:param selection: See Selection.
:param digits: See Float.
:param relation: Like model_name.
:param add_remove: See Many2One.
:param field: The field of the function.
'''
super(Property, self).__init__('', type=type, model_name=model_name,
selection=selection, digits=digits, relation=relation,
add_remove=add_remove, string=string, help=help,
required=required, readonly=readonly, domain=domain,
states=states, priority=priority, change_default=change_default,
translate=translate, select=select, on_change=on_change,
on_change_with=on_change_with, depends=depends,
order_field=order_field, context=context)
self.readonly = False
super(Property, self).__init__(field, True, True, True)
__init__.__doc__ += Field.__init__.__doc__
def __copy__(self):
return Property(copy.copy(self._field))
def get(self, cursor, user, ids, model, name, values=None, context=None):
'''
Retreive the property.
@@ -56,21 +42,21 @@ class Property(Function):
return res
def set(self, cursor, user, record_id, model, name, value, context=None):
def set(self, cursor, user, ids, model, name, value, context=None):
'''
Set the property.
:param cursor: The database cursor.
:param user: The user id.
:param record_id: The record id.
:param ids: A list of ids.
:param model: The model.
:param name: The name of the field.
:param value: The value to set.
:param context: The context.
'''
property_obj = model.pool.get('ir.property')
return property_obj.set(cursor, user, name, model._name, record_id,
(value and (self.model_name or '') + ',' + str(value)) or
return property_obj.set(cursor, user, name, model._name, ids,
(value and getattr(self, 'model_name', '') + ',' + str(value)) or
False, context=context)
+1
View File
@@ -27,6 +27,7 @@ class Reference(Field):
on_change_with=on_change_with, depends=depends,
order_field=order_field, context=context)
self.selection = selection or None
__init__.__doc__ += Field.__init__.__doc__
def get(self, cursor, user, ids, model, name, values=None, context=None):
+11 -12
View File
@@ -407,7 +407,7 @@ class ModelSQL(ModelStorage):
upd_todo.sort(lambda x, y: self._columns[x].priority - \
self._columns[y].priority)
for field in upd_todo:
self._columns[field].set(cursor, user, id_new, self, field,
self._columns[field].set(cursor, user, [id_new], self, field,
values[field], context=context)
if self._history:
@@ -601,8 +601,8 @@ class ModelSQL(ModelStorage):
func_fields = {}
for field in fields_post:
if isinstance(self._columns[field], fields.Function):
key = (self._columns[field].fnct, self._columns[field].arg,
self._columns[field].datetime_field)
key = (self._columns[field].getter,
getattr(self._columns[field], 'datetime_field', None))
func_fields.setdefault(key, [])
func_fields[key].append(field)
continue
@@ -622,10 +622,10 @@ class ModelSQL(ModelStorage):
values=res, context=context)
for record in res:
record[field] = res2[record['id']]
for i in func_fields:
field_list = func_fields[i]
for key in func_fields:
field_list = func_fields[key]
field = field_list[0]
datetime_field = i[2]
_, datetime_field = key
if datetime_field:
ctx = context.copy()
for record in res:
@@ -636,8 +636,8 @@ class ModelSQL(ModelStorage):
for field in res2:
record[field] = res2[field][record['id']]
continue
res2 = self._columns[field].get(cursor, user, ids, self, field_list,
values=res, context=context)
res2 = self._columns[field].get(cursor, user, ids, self,
field_list, values=res, context=context)
for field in res2:
for record in res:
record[field] = res2[field][record['id']]
@@ -923,13 +923,12 @@ class ModelSQL(ModelStorage):
context.get('language') or 'en_US', ids,
values[field])
# call the 'set' method of fields which are not classic_write
# call the 'set' method of fields
upd_todo.sort(lambda x, y: self._columns[x].priority - \
self._columns[y].priority)
for field in upd_todo:
for select_id in ids:
self._columns[field].set(cursor, user, select_id, self, field,
values[field], context=context)
self._columns[field].set(cursor, user, ids, self, field,
values[field], context=context)
if self._history:
columns = ['"' + str(x) + '"' for x in self._columns
+3 -4
View File
@@ -43,8 +43,8 @@ class ModelStorage(Model):
create_date = fields.DateTime('Create Date', readonly=True)
write_uid = fields.Many2One('res.user', 'Write User', readonly=True)
write_date = fields.DateTime('Write Date', readonly=True)
rec_name = fields.Function('get_rec_name', type='char', string='Name',
fnct_search='search_rec_name')
rec_name = fields.Function(fields.Char('Name'), 'get_rec_name',
searcher='search_rec_name')
def __init__(self):
super(ModelStorage, self).__init__()
@@ -437,7 +437,7 @@ class ModelStorage(Model):
return domain
return process(domain)
def get_rec_name(self, cursor, user, ids, name, arg, context=None):
def get_rec_name(self, cursor, user, ids, name, context=None):
'''
Return a dictionary with id as key and rec_name as value.
It is used by the Function field rec_name.
@@ -446,7 +446,6 @@ class ModelStorage(Model):
:param user: the user id
:param ids: a list of ids
:param name: the name of the Function field
:param arg: the argument of the Function field
:param context: the context
:return: a dictionary
'''
+3 -4
View File
@@ -158,11 +158,10 @@ SequenceTypeGroup()
class Sequence(ModelSQL, ModelView):
_name = 'ir.sequence'
groups = fields.Function('get_groups', type='many2many',
relation='res.group', string='User Groups',
fnct_search='search_groups')
groups = fields.Function(fields.Many2Many('res.group', None, None,
'User Groups'), 'get_groups', searcher='search_groups')
def get_groups(self, cursor, user, ids, name, arg, context=None):
def get_groups(self, cursor, user, ids, name, context=None):
sequence_type_obj = self.pool.get('ir.sequence.type')
sequences= self.browse(cursor, user, ids, context=context)
code2seq = {}
+3 -4
View File
@@ -56,8 +56,8 @@ class Request(ModelSQL, ModelView):
True,
Not(Equal(Eval('act_from', 0), Eval('_user', 0)))),
})
number_references = fields.Function('get_number_references', type='integer',
string="Number of References", on_change_with=['references'])
number_references = fields.Function(fields.Integer('Number of References',
on_change_with=['references']), 'get_number_references')
state = fields.Selection(_STATES, 'State', required=True, readonly=True)
history = fields.One2Many('res.request.history', 'request',
'History', readonly=True)
@@ -92,8 +92,7 @@ class Request(ModelSQL, ModelView):
return len(vals['references'])
return 0
def get_number_references(self, cursor, user, ids, name, arg,
context=None):
def get_number_references(self, cursor, user, ids, name, context=None):
res = {}
for request in self.browse(cursor, user, ids, context=context):
if request.references:
+8 -9
View File
@@ -37,15 +37,14 @@ class User(ModelSQL, ModelView):
domain=[('global_p', '!=', True), ('default_p', '!=', True)])
language = fields.Many2One('ir.lang', 'Language',
domain=['OR', ('translatable', '=', True), ('code', '=', 'en_US')])
language_direction = fields.Function('get_language_direction', type='char',
string='Language Direction')
language_direction = fields.Function(fields.Char('Language Direction'),
'get_language_direction')
timezone = fields.Selection('timezones', 'Timezone')
email = fields.Char('Email')
status_bar = fields.Function('get_status_bar', type='char',
string="Status Bar")
status_bar = fields.Function(fields.Char('Status Bar'), 'get_status_bar')
warnings = fields.One2Many('res.user.warning', 'user', 'Warnings')
connections = fields.Function('get_connections', type='integer',
string='Connections')
connections = fields.Function(fields.Integer('Connections'),
'get_connections')
def __init__(self):
super(User, self).__init__()
@@ -100,7 +99,7 @@ class User(ModelSQL, ModelView):
def default_action(self, cursor, user, context=None):
return self.default_menu(cursor, user, context=context)
def get_language_direction(self, cursor, user, ids, name, arg, context=None):
def get_language_direction(self, cursor, user, ids, name, context=None):
res = {}
lang_obj = self.pool.get('ir.lang')
default_direction = lang_obj.default_direction(cursor, user, context=context)
@@ -111,13 +110,13 @@ class User(ModelSQL, ModelView):
res[user.id] = default_direction
return res
def get_status_bar(self, cursor, user_id, ids, name, arg, context=None):
def get_status_bar(self, cursor, user_id, ids, name, context=None):
res = {}
for user in self.browse(cursor, user_id, ids, context=context):
res[user.id] = user.name
return res
def get_connections(self, cursor, user, ids, name, arg, context=None):
def get_connections(self, cursor, user, ids, name, context=None):
res = {}
for user_id in ids:
res[user_id] = get_connections(cursor.database_name, user_id)