_columns = {
# check interoperability of field inheritance with old-style fields
- 'name': osv.fields.char('Name', required=True),
+ 'name': osv.fields.char('Name'),
'state': osv.fields.selection([('a', 'A'), ('b', 'B')], string='State'),
}
+ _defaults = {
+ 'name': 'Foo',
+ }
surname = fields.Char(compute='_compute_surname')
field_in_mother = fields.Char()
- # extend the name field by adding a default value
- name = fields.Char(default='Unknown')
+ # extend the name field: make it required and change its default value
+ name = fields.Char(required=True, default='Bar')
# extend the selection of the state field
state = fields.Selection(selection_add=[('c', 'C')])
def test_field_extension(self):
""" check the extension of a field in an inherited model """
- # the field mother.name should inherit required=True, and have a default
- # value
+ # the field mother.name should inherit required=True, and have "Bar" as
+ # a default value
mother = self.env['test.inherit.mother']
field = mother._fields['name']
self.assertTrue(field.required)
- self.assertEqual(field.default(mother), 'Unknown')
+
+ self.assertEqual(field.default(mother), "Bar")
+ self.assertEqual(mother.default_get(['name']), {'name': "Bar"})
+ self.assertEqual(mother._defaults.get('name'), "Bar")
# the field daugther.template_id should inherit
# model_name='test.inherit.mother', string='Template', required=True
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)
if not self.string:
self.string = name.replace('_', ' ').capitalize()
+ # determine self.default and cls._defaults in a consistent way
+ self._determine_default(cls, name)
+
self.reset()
+ def _determine_default(self, cls, name):
+ """ Retrieve the default value for `self` in the hierarchy of `cls`, and
+ determine `self.default` and `cls._defaults` accordingly.
+ """
+ self.default = None
+
+ # traverse the class hierarchy upwards, and take the first field
+ # definition with a default or _defaults for self
+ for klass in cls.__mro__:
+ field = klass.__dict__.get(name, self)
+ if not isinstance(field, type(self)):
+ return # klass contains another value overridden by self
+
+ if 'default' in field._attrs:
+ # take the default in field, and adapt it for cls._defaults
+ value = field._attrs['default']
+ if callable(value):
+ self.default = value
+ cls._defaults[name] = lambda model, cr, uid, context: \
+ self.convert_to_write(value(model.browse(cr, uid, [], context)))
+ else:
+ self.default = lambda recs: value
+ cls._defaults[name] = value
+ return
+
+ defaults = klass.__dict__.get('_defaults') or {}
+ if name in defaults:
+ # take the value from _defaults, and adapt it for self.default
+ value = defaults[name]
+ value_func = value if callable(value) else lambda *args: value
+ self.default = lambda recs: self.convert_to_cache(
+ value_func(recs._model, recs._cr, recs._uid, recs._context),
+ recs, validate=False,
+ )
+ cls._defaults[name] = value
+ return
+
def __str__(self):
return "%s.%s" % (self.model_name, self.name)
# transform columns into new-style fields (enables field inheritance)
for name, column in self._columns.iteritems():
- if not hasattr(self, name):
- setattr(self, name, column.to_field())
+ if name in self.__dict__:
+ _logger.warning("Field %r erasing an existing value", name)
+ setattr(self, name, column.to_field())
class NewId(object):
)
columns.update(cls._columns)
- defaults = dict(parent_class._defaults)
- defaults.update(cls._defaults)
-
inherits = dict(parent_class._inherits)
inherits.update(cls._inherits)
'_name': name,
'_register': False,
'_columns': columns,
- '_defaults': defaults,
'_inherits': inherits,
'_depends': depends,
'_constraints': constraints,
'_name': name,
'_register': False,
'_columns': dict(cls._columns),
- '_defaults': dict(cls._defaults),
+ '_defaults': {}, # filled by Field._determine_default()
'_inherits': dict(cls._inherits),
'_depends': dict(cls._depends),
'_constraints': list(cls._constraints),
self[name] = self.env['ir.property'].get(name, self._name)
return
- # 4. look up _defaults
- if name in self._defaults:
- value = self._defaults[name]
- if callable(value):
- value = value(self._model, cr, uid, context)
- self[name] = value
- return
-
- # 5. delegate to field
+ # 4. delegate to field
field.determine_default(self)
def fields_get_keys(self, cr, user, context=None):
def _set_default_value_on_column(self, cr, column_name, context=None):
- # ideally should use add_default_value but fails
- # due to ir.values not being ready
+ # ideally, we should use default_get(), but it fails due to ir.values
+ # not being ready
- # get old-style default
+ # get default value
default = self._defaults.get(column_name)
if callable(default):
default = default(self, cr, SUPERUSER_ID, context)
- # get new_style default if no old-style
- if default is None:
- record = self.new(cr, SUPERUSER_ID, context=context)
- field = self._fields[column_name]
- field.determine_default(record)
- defaults = dict(record._cache)
- if column_name in defaults:
- default = field.convert_to_write(defaults[column_name])
-
column = self._columns[column_name]
ss = column._symbol_set
db_default = ss[1](default)