odoo8 默认的create方法
osv.osv -->modules.py文件中
def create(self, vals): """ create(vals) -> record Creates a new record for the model. The new record is initialized using the values from ``vals`` and if necessary those from :meth:`~.default_get`. :param dict vals: values for the model's fields, as a dictionary:: {'field_name': field_value, ...} see :meth:`~.write` for details :return: new record created :raise AccessError: * if user has no create rights on the requested object * if user tries to bypass access rules for create on the requested object :raise ValidateError: if user tries to enter invalid value for a field that is not in selection :raise UserError: if a loop would be created in a hierarchy of objects a result of the operation (such as setting an object as its own parent) """ self.check_access_rights('create') # add missing defaults, and drop fields that may not be set by user vals = self._add_missing_default_values(vals) for field in itertools.chain(MAGIC_COLUMNS, ('parent_left', 'parent_right')): vals.pop(field, None) # split up fields into old-style and pure new-style ones old_vals, new_vals, unknown = {}, {}, [] for key, val in vals.iteritems(): field = self._fields.get(key) if field: if field.column or field.inherited: old_vals[key] = val if field.inverse and not field.inherited: new_vals[key] = val else: unknown.append(key) if unknown: _logger.warning("%s.create() with unknown fields: %s", self._name, ', '.join(sorted(unknown))) # create record with old-style fields record = self.browse(self._create(old_vals)) # put the values of pure new-style fields into cache, and inverse them record._cache.update(record._convert_to_cache(new_vals)) for key in new_vals: self._fields[key].determine_inverse(record) return record def _create(self, cr, user, vals, context=None): # low-level implementation of create() if not context: context = {} if self.is_transient(): self._transient_vacuum(cr, user) tocreate = {} for v in self._inherits: if self._inherits[v] not in vals: tocreate[v] = {} else: tocreate[v] = {'id': vals[self._inherits[v]]} updates = [ # list of column assignments defined as tuples like: # (column_name, format_string, column_value) # (column_name, sql_formula) # Those tuples will be used by the string formatting for the INSERT # statement below. ('id', "nextval('%s')" % self._sequence), ] upd_todo = [] unknown_fields = [] for v in vals.keys(): if v in self._inherit_fields and v not in self._columns: (table, col, col_detail, original_parent) = self._inherit_fields[v] tocreate[table][v] = vals[v] del vals[v] else: if (v not in self._inherit_fields) and (v not in self._columns): del vals[v] unknown_fields.append(v) if unknown_fields: _logger.warning( 'No such field(s) in model %s: %s.', self._name, ', '.join(unknown_fields)) for table in tocreate: if self._inherits[table] in vals: del vals[self._inherits[table]] record_id = tocreate[table].pop('id', None) if record_id is None or not record_id: record_id = self.pool[table].create(cr, user, tocreate[table], context=context) else: self.pool[table].write(cr, user, [record_id], tocreate[table], context=context) updates.append((self._inherits[table], '%s', record_id)) #Start : Set bool fields to be False if they are not touched(to make search more powerful) bool_fields = [x for x in self._columns.keys() if self._columns[x]._type=='boolean'] for bool_field in bool_fields: if bool_field not in vals: vals[bool_field] = False #End for field in vals.keys(): fobj = None if field in self._columns: fobj = self._columns[field] else: fobj = self._inherit_fields[field][2] if not fobj: continue groups = fobj.write if groups: edit = False for group in groups: module = group.split(".")[0] grp = group.split(".")[1] cr.execute("select count(*) from res_groups_users_rel where gid IN (select res_id from ir_model_data where name='%s' and module='%s' and model='%s') and uid=%s" % \ (grp, module, 'res.groups', user)) readonly = cr.fetchall() if readonly[0][0] >= 1: edit = True break elif readonly[0][0] == 0: edit = False else: edit = False if not edit: vals.pop(field) for field in vals: current_field = self._columns[field] if current_field._classic_write: updates.append((field, '%s', current_field._symbol_set[1](vals[field]))) #for the function fields that receive a value, we set them directly in the database #(they may be required), but we also need to trigger the _fct_inv() if (hasattr(current_field, '_fnct_inv')) and not isinstance(current_field, fields.related): #TODO: this way to special case the related fields is really creepy but it shouldn't be changed at #one week of the release candidate. It seems the only good way to handle correctly this is to add an #attribute to make a field `really readonly´ and thus totally ignored by the create()... otherwise #if, for example, the related has a default value (for usability) then the fct_inv is called and it #may raise some access rights error. Changing this is a too big change for now, and is thus postponed #after the release but, definitively, the behavior shouldn't be different for related and function #fields. upd_todo.append(field) else: #TODO: this `if´ statement should be removed because there is no good reason to special case the fields #related. See the above TODO comment for further explanations. if not isinstance(current_field, fields.related): upd_todo.append(field) if field in self._columns \ and hasattr(current_field, 'selection') \ and vals[field]: self._check_selection_field_value(cr, user, field, vals[field], context=context) if self._log_access: updates.append(('create_uid', '%s', user)) updates.append(('write_uid', '%s', user)) updates.append(('create_date', "(now() at time zone 'UTC')")) updates.append(('write_date', "(now() at time zone 'UTC')")) # the list of tuples used in this formatting corresponds to # tuple(field_name, format, value) # In some case, for example (id, create_date, write_date) we does not # need to read the third value of the tuple, because the real value is # encoded in the second value (the format). cr.execute( """INSERT INTO "%s" (%s) VALUES(%s) RETURNING id""" % ( self._table, ', '.join('"%s"' % u[0] for u in updates), ', '.join(u[1] for u in updates) ), tuple([u[2] for u in updates if len(u) > 2]) ) id_new, = cr.fetchone() recs = self.browse(cr, user, id_new, context) if self._parent_store and not context.get('defer_parent_store_computation'): if self.pool._init: self.pool._init_parent[self._name] = True else: parent = vals.get(self._parent_name, False) if parent: cr.execute('select parent_right from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (parent,)) pleft_old = None result_p = cr.fetchall() for (pleft,) in result_p: if not pleft: break pleft_old = pleft if not pleft_old: cr.execute('select parent_left from '+self._table+' where id=%s', (parent,)) pleft_old = cr.fetchone()[0] pleft = pleft_old else: cr.execute('select max(parent_right) from '+self._table) pleft = cr.fetchone()[0] or 0 cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%s', (pleft,)) cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,)) cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1, pleft+2, id_new)) recs.invalidate_cache(['parent_left', 'parent_right']) # invalidate and mark new-style fields to recompute; do this before # setting other fields, because it can require the value of computed # fields, e.g., a one2many checking constraints on records recs.modified(self._fields) # call the 'set' method of fields which are not classic_write upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority) # default element in context must be remove when call a one2many or many2many rel_context = context.copy() for c in context.items(): if c[0].startswith('default_'): del rel_context[c[0]] result = [] for field in upd_todo: result += self._columns[field].set(cr, self, id_new, field, vals[field], user, rel_context) or [] # for recomputing new-style fields recs.modified(upd_todo) # check Python constraints recs._validate_fields(vals) if context.get('recompute', True): result += self._store_get_values(cr, user, [id_new], list(set(vals.keys() + self._inherits.values())), context) result.sort() done = [] for order, model_name, ids, fields2 in result: if not (model_name, ids, fields2) in done: self.pool[model_name]._store_set_values(cr, user, ids, fields2, context) done.append((model_name, ids, fields2)) # recompute new-style fields recs.recompute() if self._log_create and context.get('recompute', True): message = self._description + \ " '" + \ self.name_get(cr, user, [id_new], context=context)[0][1] + \ "' " + _("created.") self.log(cr, user, id_new, message, True, context=context) self.check_access_rule(cr, user, [id_new], 'create', context=context) self.create_workflow(cr, user, [id_new], context=context) return id_new
版权声明:本文为zhangfeng1133原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。