related = None # sequence of field names, for related fields
related_sudo = True # whether related fields should be read as admin
company_dependent = False # whether `self` is company-dependent (property field)
- default = None # default value (literal or callable)
+ default = None # default(recs) returns the default value
string = None # field label
help = None # field tooltip
attrs.update(self._attrs) # necessary in case self is not in cls
# initialize `self` with `attrs`
+ if 'default' in attrs and not callable(attrs['default']):
+ # make default callable
+ value = attrs['default']
+ attrs['default'] = lambda recs: value
if attrs.get('compute'):
# by default, computed fields are not stored, not copied and readonly
attrs['store'] = attrs.get('store', False)
def to_column(self):
""" return a low-level field object corresponding to `self` """
assert self.store
- if self.column:
- # some columns are registry-dependent, like float fields (digits);
- # duplicate them to avoid sharing between registries
- return copy(self.column)
+ # some columns are registry-dependent, like float fields (digits);
+ # duplicate them to avoid sharing between registries
_logger.debug("Create fields._column for Field %s", self)
args = {}
for attr, prop in self.column_attrs:
args['relation'] = self.comodel_name
return fields.property(**args)
+ if isinstance(self.column, fields.function):
+ # it is too tricky to recreate a function field, so for that case,
+ # we make a stupid (and possibly incorrect) copy of the column
+ return copy(self.column)
+
return getattr(fields, self.type)(**args)
# properties used by to_column() to create a column instance
def determine_default(self, record):
""" determine the default value of field `self` on `record` """
- if self.default is not None:
- value = self.default(record) if callable(self.default) else self.default
+ if self.default:
+ value = self.default(record)
record._cache[self] = self.convert_to_cache(value, record)
elif self.compute:
self._compute_value(record)
field = self.related_field
self.selection = lambda model: field._description_selection(model.env)
- def _setup_regular(self, env):
- super(Selection, self)._setup_regular(env)
- # determine selection (applying extensions)
- cls = type(env[self.model_name])
+ def set_class_name(self, cls, name):
+ super(Selection, self).set_class_name(cls, name)
+ # determine selection (applying 'selection_add' extensions)
selection = None
- for field in resolve_all_mro(cls, self.name, reverse=True):
+ for field in resolve_all_mro(cls, name, reverse=True):
if isinstance(field, type(self)):
# We cannot use field.selection or field.selection_add here
# because those attributes are overridden by `set_class_name`.
def __init__(self, comodel_name=None, string=None, **kwargs):
super(Many2one, self).__init__(comodel_name=comodel_name, string=string, **kwargs)
- def _setup_regular(self, env):
- super(Many2one, self)._setup_regular(env)
-
- # self.inverse_fields is populated by the corresponding One2many field
-
+ def set_class_name(self, cls, name):
+ super(Many2one, self).set_class_name(cls, name)
# determine self.delegate
- self.delegate = self.name in env[self.model_name]._inherits.values()
+ if not self.delegate:
+ self.delegate = name in cls._inherits.values()
_column_ondelete = property(attrgetter('ondelete'))
_column_auto_join = property(attrgetter('auto_join'))