X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=openerp%2Fmodels.py;h=2562e1084102e3f79bcd163558914c9b1be9e1df;hb=36174fcc6e49fe11ed16325b229690bb48736e62;hp=da53a7633767368c9a40c56f07a259b3a26a19d0;hpb=f2299749fe234138df8751d0aeff7559fafdeb05;p=odoo%2Fodoo.git diff --git a/openerp/models.py b/openerp/models.py index da53a76..2562e10 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -39,7 +39,6 @@ """ -import copy import datetime import functools import itertools @@ -239,8 +238,9 @@ class MetaModel(api.Meta): # 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): @@ -479,6 +479,18 @@ class BaseModel(object): cls._columns.pop(name, None) @classmethod + def _pop_field(cls, name): + """ Remove the field with the given `name` from the model. + This method should only be used for manual fields. + """ + field = cls._fields.pop(name) + cls._columns.pop(name, None) + cls._all_columns.pop(name, None) + if hasattr(cls, name): + delattr(cls, name) + return field + + @classmethod def _add_magic_fields(cls): """ Introduce magic fields on the current class @@ -591,9 +603,6 @@ class BaseModel(object): ) columns.update(cls._columns) - defaults = dict(parent_class._defaults) - defaults.update(cls._defaults) - inherits = dict(parent_class._inherits) inherits.update(cls._inherits) @@ -618,7 +627,6 @@ class BaseModel(object): '_name': name, '_register': False, '_columns': columns, - '_defaults': defaults, '_inherits': inherits, '_depends': depends, '_constraints': constraints, @@ -632,7 +640,7 @@ class BaseModel(object): '_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), @@ -641,12 +649,6 @@ class BaseModel(object): } cls = type(cls._name, (cls,), attrs) - # float fields are registry-dependent (digit attribute); duplicate them - # to avoid issues - for key, col in cls._columns.items(): - if col._type == 'float': - cls._columns[key] = copy.copy(col) - # instantiate the model, and initialize it model = object.__new__(cls) model.__init__(pool, cr) @@ -808,7 +810,7 @@ class BaseModel(object): # inheritance between different models) cls._fields = {} for attr, field in getmembers(cls, Field.__instancecheck__): - if not field._origin: + if not field.inherited: cls._add_field(attr, field.copy()) # introduce magic fields @@ -1364,15 +1366,7 @@ class BaseModel(object): 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): @@ -2266,28 +2260,13 @@ class BaseModel(object): if val is not False: cr.execute(update_query, (ss[1](val), key)) - def _check_selection_field_value(self, cr, uid, field, value, context=None): - """Raise except_orm if value is not among the valid values for the selection field""" - if self._columns[field]._type == 'reference': - val_model, val_id_str = value.split(',', 1) - val_id = False - try: - val_id = long(val_id_str) - except ValueError: - pass - if not val_id: - raise except_orm(_('ValidateError'), - _('Invalid value for reference field "%s.%s" (last part must be a non-zero integer): "%s"') % (self._table, field, value)) - val = val_model - else: - val = value - if isinstance(self._columns[field].selection, (tuple, list)): - if val in dict(self._columns[field].selection): - return - elif val in dict(self._columns[field].selection(self, cr, uid, context=context)): - return - raise except_orm(_('ValidateError'), - _('The value "%s" for the field "%s.%s" is not in the selection') % (value, self._name, field)) + @api.model + def _check_selection_field_value(self, field, value): + """ Check whether value is among the valid values for the given + selection/reference field, and raise an exception if not. + """ + field = self._fields[field] + field.convert_to_cache(value, self) def _check_removed_columns(self, cr, log=False): # iterate on the database columns to drop the NOT NULL constraints @@ -2423,23 +2402,14 @@ class BaseModel(object): 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) @@ -2490,8 +2460,8 @@ class BaseModel(object): self._create_table(cr) has_rows = False else: - cr.execute('SELECT min(id) FROM "%s"' % (self._table,)) - has_rows = cr.fetchone()[0] is not None + cr.execute('SELECT 1 FROM "%s" LIMIT 1' % self._table) + has_rows = cr.rowcount cr.commit() if self._parent_store: @@ -2945,9 +2915,9 @@ class BaseModel(object): for attr, field in cls.pool[parent_model]._fields.iteritems(): if attr not in cls._fields: cls._add_field(attr, field.copy( + inherited=True, related=(parent_field, attr), related_sudo=False, - _origin=field, )) cls._inherits_reload_src() @@ -2998,7 +2968,9 @@ class BaseModel(object): """ Setup the fields (dependency triggers, etc). """ for field in self._fields.itervalues(): if partial and field.manual and \ - field.relational and field.comodel_name not in self.pool: + field.relational and \ + (field.comodel_name not in self.pool or \ + (field.type == 'one2many' and field.inverse_name not in self.pool[field.comodel_name]._fields)): # do not set up manual fields that refer to unknown models continue field.setup(self.env) @@ -3035,6 +3007,8 @@ class BaseModel(object): for fname, field in self._fields.iteritems(): if allfields and fname not in allfields: continue + if not field.setup_done: + continue if field.groups and not recs.user_has_groups(field.groups): continue res[fname] = field.get_description(recs.env) @@ -3694,6 +3668,7 @@ class BaseModel(object): readonly = None self.check_field_access_rights(cr, user, 'write', vals.keys()) + deleted_related = defaultdict(list) for field in vals.keys(): fobj = None if field in self._columns: @@ -3702,6 +3677,10 @@ class BaseModel(object): fobj = self._inherit_fields[field][2] if not fobj: continue + if fobj._type in ['one2many', 'many2many'] and vals[field]: + for wtuple in vals[field]: + if isinstance(wtuple, (tuple, list)) and wtuple[0] == 2: + deleted_related[fobj._obj].append(wtuple[1]) groups = fobj.write if groups: @@ -3905,7 +3884,8 @@ class BaseModel(object): for id in ids_to_update: if id not in done[key]: done[key][id] = True - todo.append(id) + if id not in deleted_related[model_name]: + todo.append(id) self.pool[model_name]._store_set_values(cr, user, todo, fields_to_recompute, context) # recompute new-style fields