You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo技术问询:如何延迟加载不可存储计算字段以加速页面加载?

Odoo不可存储计算字段延迟加载方案

针对不可存储计算字段拖慢页面加载的问题,以下是几个兼顾实时性和性能的可行延迟加载方案:

1. 前端异步加载(通用方案)

页面初始加载时只渲染非计算字段,计算字段先用加载中...这类占位符显示,待页面渲染完成后,通过Odoo的RPC API异步请求计算字段数据并更新DOM。

实现步骤:

  • 在视图XML中给计算字段添加自定义类名,并设置初始占位:
    <!-- 看板视图示例 -->
    <kanban>
      <templates>
        <t t-name="kanban-box">
          <div class="oe_kanban_global_click">
            <div class="lazy-compute-field" data-field="my_computed_field" data-record-id="record.id.raw_value">加载中...</div>
          </div>
        </t>
      </templates>
    </kanban>
    
    <!-- 表单视图示例 -->
    <form>
      <field name="my_computed_field" class="lazy-compute-field" attrs="{'invisible': [('id', '=', False)]}"/>
    </form>
    
  • 添加前端JS代码,批量请求并更新数据:
    odoo.define('my_module.lazy_load_fields', function (require) {
        "use strict";
        var core = require('web.core');
        var rpc = require('web.rpc');
    
        core.bus.on('web_client_ready', null, function () {
            // 处理看板视图
            const kanbanFields = document.querySelectorAll('.lazy-compute-field[data-record-id]');
            if (kanbanFields.length) {
                const recordIds = Array.from(kanbanFields).map(el => el.dataset.recordId);
                rpc.query({
                    model: 'your.model.name',
                    method: 'get_computed_fields',
                    args: [recordIds, ['my_computed_field']],
                }).then(result => {
                    kanbanFields.forEach(el => {
                        const recordId = el.dataset.recordId;
                        el.textContent = result[recordId].my_computed_field || '-';
                    });
                });
            }
    
            // 处理表单视图
            const formView = document.querySelector('.o_form_view .lazy-compute-field');
            if (formView) {
                const recordId = formView.closest('.o_form_view').dataset.recordId;
                rpc.query({
                    model: 'your.model.name',
                    method: 'get_computed_fields',
                    args: [[recordId], ['my_computed_field']],
                }).then(result => {
                    formView.textContent = result[recordId].my_computed_field || '-';
                });
            }
        });
    });
    
  • 后端添加批量获取计算字段的方法:
    from odoo import models, api
    
    class YourModel(models.Model):
        _inherit = 'your.model.name'
    
        @api.multi
        def get_computed_fields(self, field_names):
            result = {}
            for record in self:
                result[record.id] = {field: getattr(record, field) for field in field_names}
            return result
    

2. 看板视图滚动触发加载

利用Intersection Observer API,仅当看板卡片进入可视区域时才加载对应计算字段,进一步减少初始请求量。

实现调整:

修改前端JS为监听元素可见性:

odoo.define('my_module.lazy_load_kanban', function (require) {
    "use strict";
    var core = require('web.core');
    var rpc = require('web.rpc');

    core.bus.on('kanban_view_loaded', null, function () {
        const observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const el = entry.target;
                    const recordId = el.dataset.recordId;
                    const fieldName = el.dataset.field;
                    rpc.query({
                        model: 'your.model.name',
                        method: 'get_computed_fields',
                        args: [[recordId], [fieldName]],
                    }).then(result => {
                        el.textContent = result[recordId][fieldName] || '-';
                    });
                    observer.unobserve(el);
                }
            });
        });

        document.querySelectorAll('.lazy-compute-field[data-record-id]').forEach(el => {
            observer.observe(el);
        });
    });
});

3. 表单视图标签页延迟加载

将计算字段放到单独标签页,只有用户切换到该标签页时才触发数据加载。

实现步骤:

  • 视图XML拆分标签页:
<form>
    <sheet>
        <notebook>
            <page string="基本信息">
                <field name="name"/>
                <field name="create_date"/>
            </page>
            <page string="实时计算数据" class="lazy-compute-tab">
                <field name="my_computed_field" class="lazy-compute-field"/>
                <field name="another_computed_field" class="lazy-compute-field"/>
            </page>
        </notebook>
    </sheet>
</form>
  • 前端监听标签页切换事件:
odoo.define('my_module.lazy_load_form_tab', function (require) {
    "use strict";
    var core = require('web.core');
    var rpc = require('web.rpc');

    core.bus.on('tab_changed', null, function (tab) {
        if (tab.classList.contains('lazy-compute-tab')) {
            const formView = tab.closest('.o_form_view');
            const recordId = formView.dataset.recordId;
            const fields = Array.from(tab.querySelectorAll('.lazy-compute-field')).map(el => el.name);
            rpc.query({
                model: 'your.model.name',
                method: 'get_computed_fields',
                args: [[recordId], fields],
            }).then(result => {
                fields.forEach(field => {
                    const el = tab.querySelector(`[name="${field}"]`);
                    el.textContent = result[recordId][field] || '-';
                });
            });
        }
    });
});

4. 后端计算逻辑优化(辅助方案)

即使做了延迟加载,优化计算逻辑本身也能提升请求响应速度:

  • 批量计算:确保计算字段使用@api.multi,用self.mapped()或批量ORM操作避免循环查询。
  • 减少关联查询:通过prefetch提前加载关联模型数据,解决N+1查询问题。
  • 轻量级缓存:若实时性要求不是毫秒级,可给计算字段加cache=True,Odoo会基于依赖字段自动失效缓存:
    @api.depends('dependency_field1', 'dependency_field2')
    @api.multi
    @api.depends_context('uid')  # 依赖当前用户时添加上下文依赖
    def _compute_my_field(self):
        for record in self:
            record.my_computed_field = record.dependency_field1 + record.dependency_field2
    

内容的提问来源于stack exchange,提问作者Scott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 04:06:18