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
相关产品推荐
相关产品推荐

