【转载】odoo技术开发白皮书 第三部分 第六章 基础模型

转载:http://book.odoomommy.com/chapter3/README6.html

第六章 基础模型

基础模型(Basic Model)包含了Python模型数据与web client通信所必须的全部业务逻辑,其作用是给出了一个对其余的web client对象来说足够简单和统一的API,以帮助它们(视图、字段Widget)来实现查询和更新数据库中的数据 的需求。

基础模型本质上是一个哈希字典,其值可能是整数、对象或者元对象。每个哈希字典的对象都代表了一小块数据,并且可以通过id作为key进行重载或者更新。

下面是一个数据点(data point)的样例:

var dataPoint = {
    _cache: {Object|undefined}
    _changes: {Object|null},
    aggregateValues: {Object},
    context: {Object},
    count: {integer},
    data: {Object|Object[]},
    domain: {*[]},
    fields: {Object},
    fieldsInfo: {Object},
    getContext: {function},
    getDomain: {function},
    getFieldNames: {function},
    groupedBy: {string[]},
    id: {integer},
    isOpen: {boolean},
    loadMoreOffset: {integer},
    limit: {integer},
    model: {string},
    offset: {integer},
    openGroupByDefault: {boolean},
    orderedBy: {Object[]},
    orderedResIDs: {integer[]},
    parentID: {string},
    rawContext: {Object},
    relationField: {string},
    res_id: {integer|null},
    res_ids: {integer[]},
    specialData: {Object},
    _specialDataCache: {Object},
    static: {boolean},
    type: {string} 'record' | 'list'
    value: ?,
};

需要注意的几点:

  • id: 与res_id完全没有关系的id,是web client端的概念,与数据库中的记录没有任何关系。
  • res_id: 数据库中的记录id,如果它的值是数字或者虚拟ID(虚拟ID是一个由数字和中划线和其他信息组成的字符串),它是一个数据库中真实存在的记录。如果它的值是一个virtual_和数字组成的值,那么它就是一个还未保存到数据库中的值(通常出现在create模式中)。
  • res_ids: 代表了数据点被使用的上下文。举例来说,在list视图中打开了某一个form记录,假设被打开的记录是1,那么res_id=1,而res_ids可能的值是[1,2,3]。
  • offset: 分页中使用,如果需要加载另外一页时使用。
  • count: 被操作的记录数,不能使用res_id的原因是,res_ids的数据可能很大,或者由于domain或分页的原因,res_ids的值并非全部的数据。
  • model: 模型的名称,例如'res.partner'
  • fields: 从模型中获取的所有的字段的描述信息,它的属性可能被视图更新,所以字段类型依赖于数据点的上下文。
  • fields_names: 相关字段名称组成的列表,通常,它暗示了视图中出现的字段列表,只有出现在视图中的字段才应该被加载到这里。
  • _cache和_changes都是私有属性,不应该在Model外被使用。

特性

我们知道分组视图可以显示某些列的汇总信息,那么什么类型的字段可以被分组,是由BasicModel的AGGREGATABLE_TYPES属性指定的,只有三种字段可以被分组: float、integer和monetary。

const AGGREGATABLE_TYPES = ['float', 'integer', 'monetary'];

我们知道x2many字段有一组命令用来创建或者更新记录的值,同样的,在web client中更新x2many字段的值也是用的同一组命令(0-6),稍微不同的是[0,_,valus]命令的参数是一个virtual id,它意味着当此命令给到基础模型时,它会产生一个virtual_加数字类型的记录Id, 系统用它来定位元素或者之后进行更新。

var x2ManyCommands = {
    // (0, virtualID, {values})
    CREATE: 0,
    create: function (virtualID, values) {
        delete values.id;
        return [x2ManyCommands.CREATE, virtualID || false, values];
    },
    // (1, id, {values})
    UPDATE: 1,
    update: function (id, values) {
        delete values.id;
        return [x2ManyCommands.UPDATE, id, values];
    },
    // (2, id[, _])
    DELETE: 2,
    delete: function (id) {
        return [x2ManyCommands.DELETE, id, false];
    },
    // (3, id[, _]) removes relation, but not linked record itself
    FORGET: 3,
    forget: function (id) {
        return [x2ManyCommands.FORGET, id, false];
    },
    // (4, id[, _])
    LINK_TO: 4,
    link_to: function (id) {
        return [x2ManyCommands.LINK_TO, id, false];
    },
    // (5[, _[, _]])
    DELETE_ALL: 5,
    delete_all: function () {
        return [5, false, false];
    },
    // (6, _, ids) replaces all linked records with provided ids
    REPLACE_WITH: 6,
    replace_with: function (ids) {
        return [6, false, ids];
    }
};

从代码中,我们可以总结出来一点,就是对web client的x2many Widget而言其实不存在什么更新编辑之说,其编辑的本质是先进行删除又重新创建,这个特性造成的结果就是(我们在onchange一章中提到过),onchange事件返回的永远是一个新创建的NewID,而不是原先的记录ID。

属性

基础模型中有一个属性OPEN_GROUP_LIMIT, 意思是当数据量超过这个数据,分组将进行折叠操作。还有一个属性noCacheModels,是一个模型列表,此列表中的模型在进行操作时将不作缓存处理。

OPEN_GROUP_LIMIT: 10, // after this limit, groups are automatically folded

// list of models for which the DataManager's cache should be cleared on
// create, update and delete operations
noCacheModels: [
    'ir.actions.act_window',
    'ir.filters',
    'ir.ui.view',
]

初始化

基础模型的初始化过程,先实例化了一个互斥锁,用来确保操作能够按序进行。然后初始化了一个批量RPC请求属性batchedRPCsRequests,然后实例化了一个空对象localData用来存储后续的数据。

init: function () {
    // this mutex is necessary to make sure some operations are done
    // sequentially, for example, an onchange needs to be completed before a
    // save is performed.
    this.mutex = new concurrency.Mutex();

    // this array is used to accumulate RPC requests done in the same call
    // stack, so that they can be batched in the minimum number of RPCs
    this.batchedRPCsRequests = [];

    this.localData = Object.create(null);
    this._super.apply(this, arguments);
},

公开方法

addDefaultRecord

给list对象添加默认记录,方法接受两个参数,listID和options,listID是数据集中的id,options的参数只有一个position,其值可以为top或者bottom,表示新记录应该出现在列表的顶部还是底部,默认为top。

addDefaultRecord: function (listID, options) {
    var self = this;
    var list = this.localData[listID];
    var context = _.extend({}, this._getDefaultContext(list), this._getContext(list));

    var position = (options && options.position) || 'top';
    var params = {
        context: context,
        fields: list.fields,
        fieldsInfo: list.fieldsInfo,
        parentID: list.id,
        position: position,
        viewType: list.viewType,
    };
    return this._makeDefaultRecord(list.model, params).then(function (id) {
        list.count++;
        if (position === 'top') {
            list.data.unshift(id);
        } else {
            list.data.push(id);
        }
        var record = self.localData[id];
        list._cache[record.res_id] = id;
        return id;
    });
}

此方法实际上使用了_makeDefaultRecord方法创建了一个新的记录,然后将其添加到了list对象中,默认记录直接被添加到了数据中,也就意味着只能被List或者看板控制器使用(对于x2many字段来说,实际存储的是命令组)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值