odoo8 默认的create方法

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版权协议,转载请附上原文出处链接和本声明。