Files
tryton/trytond/model/fields/function.py
T

153 lines
5.3 KiB
Python
Raw Normal View History

2014-12-02 12:54:01 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
2009-02-03 18:58:25 +01:00
2010-03-11 16:42:50 +01:00
import inspect
import copy
2018-12-29 14:19:08 +01:00
from trytond.i18n import gettext
2009-02-03 18:58:25 +01:00
from trytond.model.fields.field import Field
from trytond.tools import is_instance_method
2014-09-17 21:43:53 +02:00
from trytond.transaction import Transaction
2009-02-03 18:58:25 +01:00
class Function(Field):
2009-03-01 13:37:31 +01:00
'''
2009-09-13 15:37:11 +02:00
Define function field (any).
2009-03-01 13:37:31 +01:00
'''
2009-02-03 18:58:25 +01:00
2011-01-07 10:58:43 +01:00
def __init__(self, field, getter, setter=None, searcher=None,
loading='lazy'):
2009-03-01 13:37:31 +01:00
'''
2010-03-11 16:42:50 +01:00
: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.
2011-01-07 10:58:43 +01:00
:param loading: Define how the field must be loaded:
``lazy`` or ``eager``.
2009-03-01 13:37:31 +01:00
'''
2010-03-11 16:42:50 +01:00
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
2012-04-01 23:08:15 +02:00
assert loading in ('lazy', 'eager'), \
'loading must be "lazy" or "eager"'
2011-01-07 10:58:43 +01:00
self.loading = loading
2009-03-01 13:37:31 +01:00
__init__.__doc__ += Field.__init__.__doc__
2009-02-03 18:58:25 +01:00
2010-03-11 16:42:50 +01:00
def __copy__(self):
return Function(copy.copy(self._field), self.getter,
setter=self.setter, searcher=self.searcher, loading=self.loading)
2012-09-24 22:16:53 +02:00
def __deepcopy__(self, memo):
return Function(copy.deepcopy(self._field, memo), self.getter,
setter=self.setter, searcher=self.searcher, loading=self.loading)
2012-09-24 22:16:53 +02:00
2010-03-11 16:42:50 +01:00
def __getattr__(self, name):
return getattr(self._field, name)
2010-03-11 16:42:50 +01:00
def __getitem__(self, name):
return self._field[name]
2010-03-11 16:42:50 +01:00
def __setattr__(self, name, value):
2012-09-24 22:16:53 +02:00
if name in ('_field', '_type', 'getter', 'setter', 'searcher', 'name'):
object.__setattr__(self, name, value)
if name != 'name':
return
setattr(self._field, name, value)
2017-02-01 16:11:00 +01:00
def set_rpc(self, model):
self._field.set_rpc(model)
2017-04-01 19:55:35 +02:00
def sql_format(self, value):
return self._field.sql_format(value)
def sql_type(self):
2016-07-29 10:51:53 +02:00
return None
2013-09-06 22:32:37 +02:00
def convert_domain(self, domain, tables, Model):
name, operator, value = domain[:3]
assert name.startswith(self.name)
method = getattr(Model, 'domain_%s' % self.name, None)
if method:
return method(domain, tables)
if self.searcher:
return getattr(Model, self.searcher)(self.name, domain)
2018-12-29 14:19:08 +01:00
raise NotImplementedError(gettext(
'ir.msg_search_function_missing',
**Model.__names__(self.name)))
2009-02-03 18:58:25 +01:00
2012-09-24 22:16:53 +02:00
def get(self, ids, Model, name, values=None):
2009-03-01 13:37:31 +01:00
'''
2010-03-11 16:42:50 +01:00
Call the getter.
2009-03-01 13:37:31 +01:00
If the function has ``names`` in the function definition then
it will call it with a list of name.
'''
2014-09-17 21:43:53 +02:00
with Transaction().set_context(_check_access=False):
method = getattr(Model, self.getter)
instance_method = is_instance_method(Model, self.getter)
2018-06-26 19:11:19 +02:00
signature = inspect.signature(method)
uses_names = 'names' in signature.parameters
2014-09-17 21:43:53 +02:00
def call(name):
records = Model.browse(ids)
if not instance_method:
2014-09-17 21:43:53 +02:00
return method(records, name)
else:
return dict((r.id, method(r, name)) for r in records)
if isinstance(name, list):
names = name
2018-06-26 19:11:19 +02:00
if uses_names:
2014-09-17 21:43:53 +02:00
return call(names)
return dict((name, call(name)) for name in names)
2012-09-24 22:16:53 +02:00
else:
2018-06-26 19:11:19 +02:00
if uses_names:
2014-09-17 21:43:53 +02:00
name = [name]
return call(name)
2009-02-03 18:58:25 +01:00
2014-02-24 19:15:57 +01:00
def set(self, Model, name, ids, value, *args):
2009-03-01 13:37:31 +01:00
'''
2010-03-11 16:42:50 +01:00
Call the setter.
2009-03-01 13:37:31 +01:00
'''
2014-09-17 21:43:53 +02:00
with Transaction().set_context(_check_access=False):
if self.setter:
# TODO change setter API to use sequence of records, value
setter = getattr(Model, self.setter)
args = iter((ids, value) + args)
for ids, value in zip(args, args):
setter(Model.browse(ids), name, value)
else:
raise NotImplementedError(gettext(
'ir.msg_setter_function_missing',
**Model.__names__(self.name)))
2012-09-24 22:16:53 +02:00
def __set__(self, inst, value):
self._field.__set__(inst, value)
2019-02-13 10:37:40 +01:00
def definition(self, model, language):
definition = self._field.definition(model, language)
definition.update(super().definition(model, language))
definition['searchable'] &= (
bool(self.searcher) or hasattr(model, 'domain_' + self.name))
definition['sortable'] &= hasattr(model, 'order_' + self.name)
return definition
class MultiValue(Function):
def __init__(self, field, loading='lazy'):
super(MultiValue, self).__init__(
field, '_multivalue_getter', setter='_multivalue_setter',
loading=loading)
def __copy__(self):
return MultiValue(copy.copy(self._field), loading=self.loading)
def __deepcopy__(self, memo):
return MultiValue(
copy.deepcopy(self._field, memo), loading=self.loading)