Odoo 18 导出Excel功能知识点与流程总结
一、功能概述
在Odoo 18中实现列表数据导出Excel功能,支持选中记录或全部记录导出,生成格式化的Excel文件。
二、技术架构
2.1 核心组件
┌─────────────────────────────────────────────────────────┐
│ 用户界面层 │
│ (列表视图 + ir.actions.server 按钮) │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 模型层 (Model) │
│ action_export_excel() → 生成URL │
│ get_excel_file() → 生成Excel二进制数据 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 控制器层 (Controller) │
│ /cs_quality/export_excel → HTTP路由处理 │
│ 接收请求 → 获取记录 → 调用模型方法 → 返回文件 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 文件生成层 │
│ xlsxwriter库 → 创建Excel工作簿 → 写入数据 → 返回二进制 │
└─────────────────────────────────────────────────────────┘
2.2 文件结构
hx_cs_quality_control/
├── models/
│ └── measurement_data.py # 模型方法:生成Excel数据
├── controllers/
│ └── controllers.py # HTTP路由:处理文件下载
└── views/
└── measurement_data_views.xml # 视图配置:导出按钮
三、核心知识点
3.1 Odoo Server Action (ir.actions.server)
作用:在列表视图中添加自定义动作按钮
关键字段:
-
model_id: 执行动作的模型(Many2one到ir.model) -
binding_model_id: 绑定到哪个模型的视图(Many2one到ir.model) -
binding_view_types: 绑定到哪些视图类型(如:list, form) -
state: 动作类型(code表示执行Python代码) -
code: 执行的Python代码
示例配置:
<record id="action_export_excel" model="ir.actions.server">
<field name="name">导出Excel</field>
<field name="model_id" ref="model_cs_quality_measurement_data"/>
<field name="binding_model_id" ref="model_cs_quality_measurement_data"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
action = records.action_export_excel()
</field>
</record>
注意事项:
-
在
code中,records变量自动包含选中的记录集 -
返回的
action必须是有效的动作字典
3.2 ir.actions.act_url
作用:返回URL动作,用于跳转到指定URL
关键字段:
-
type: 固定为'ir.actions.act_url' -
url: 要跳转的URL -
target: 打开方式('self’表示当前窗口,'new’表示新窗口)
示例:
return {
'type': 'ir.actions.act_url',
'url': f'/cs_quality/export_excel?ids={ids_str}',
'target': 'self',
}
3.3 HTTP Controller路由
路由装饰器:
@http.route('/cs_quality/export_excel', type='http', auth='user', methods=['GET'], csrf=False)
参数说明:
-
type='http': HTTP类型路由(返回文件) -
auth='user': 需要用户认证 -
methods=['GET']: 允许的HTTP方法 -
csrf=False: 禁用CSRF保护(文件下载通常不需要)
文件响应:
return request.make_response(
excel_data, # 二进制数据
headers=[
('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
('Content-Disposition', content_disposition(filename)),
]
)
关键点:
-
Content-Type: 指定MIME类型为Excel文件 -
Content-Disposition: 指定文件名和下载方式 -
content_disposition(): Odoo工具函数,处理文件名编码
3.4 xlsxwriter库使用
创建工作簿:
import xlsxwriter
import io
output = io.BytesIO() # 内存中的字节流
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet('测量数据')
定义格式:
# 表头格式
header_format = workbook.add_format({
'bold': True,
'bg_color': '#366092',
'font_color': '#FFFFFF',
'align': 'center',
'valign': 'vcenter',
'border': 1,
'font_size': 11
})
# 数字格式
number_format = workbook.add_format({
'num_format': '0.000000', # 保留6位小数
'align': 'center',
'border': 1
})
# 日期格式
date_format = workbook.add_format({
'num_format': 'yyyy-mm-dd hh:mm:ss',
'align': 'center',
'border': 1
})
写入数据:
# 写入表头
worksheet.write(0, col, header, header_format)
# 写入数字
worksheet.write_number(row, col, value, number_format)
# 写入日期时间
worksheet.write_datetime(row, col, datetime_value, date_format)
# 写入普通文本
worksheet.write(row, col, text, data_format)
设置列宽:
worksheet.set_column(col, col, width) # 设置单列宽度
关闭和获取数据:
workbook.close()
output.seek(0) # 重置指针到开头
return output.getvalue() # 获取二进制数据
3.5 模型外部ID引用
问题:在XML中引用模型时,需要模型的外部ID
解决方案:显式定义ir.model记录
<record id="model_cs_quality_measurement_data" model="ir.model">
<field name="name">测量数据明细</field>
<field name="model">cs.quality.measurement.data</field>
</record>
引用方式:
<field name="model_id" ref="model_cs_quality_measurement_data"/>
四、完整流程
4.1 用户操作流程
1. 用户打开"测量数据"列表视图
↓
2. 用户选择要导出的记录(可选,不选则导出全部)
↓
3. 用户点击"动作"菜单 → "导出Excel"
↓
4. 系统执行server action代码
↓
5. 跳转到导出URL
↓
6. 浏览器下载Excel文件
4.2 代码执行流程
┌─────────────────────────────────────────────────────────┐
│ 步骤1: 用户点击按钮 │
│ 触发: ir.actions.server (code) │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤2: 执行模型方法 │
│ measurement_data.action_export_excel() │
│ - 获取记录ID列表 │
│ - 构建URL: /cs_quality/export_excel?ids=1,2,3 │
│ - 返回ir.actions.act_url动作 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤3: 浏览器跳转到URL │
│ GET /cs_quality/export_excel?ids=1,2,3 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤4: Controller处理请求 │
│ controllers.export_excel() │
│ - 解析URL参数(ids) │
│ - 获取记录集: env['cs.quality.measurement.data'].browse()│
│ - 调用模型方法生成Excel │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤5: 生成Excel文件 │
│ measurement_data.get_excel_file() │
│ - 创建xlsxwriter工作簿 │
│ - 定义格式(表头、数据、数字、日期等) │
│ - 写入表头 │
│ - 循环写入数据行 │
│ - 设置列宽 │
│ - 关闭工作簿,返回二进制数据 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤6: 返回文件响应 │
│ request.make_response() │
│ - 设置Content-Type │
│ - 设置Content-Disposition(文件名) │
│ - 返回二进制数据 │
└──────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 步骤7: 浏览器下载文件 │
│ 文件名: 测量数据导出_YYYYMMDD_HHMMSS.xlsx │
└─────────────────────────────────────────────────────────┘
4.3 数据流转图
用户选择记录
│
▼
[records对象] (Odoo记录集)
│
├─→ action_export_excel()
│ └─→ 生成URL字符串
│
└─→ get_excel_file()
│
├─→ 遍历records
│ ├─→ 读取字段值
│ ├─→ 数据转换(状态映射、日期格式化等)
│ └─→ 写入Excel单元格
│
└─→ 返回bytes二进制数据
│
└─→ HTTP响应
└─→ 浏览器下载
五、关键代码片段
5.1 模型方法 - 生成URL动作
def action_export_excel(self):
"""导出测量数据到Excel - 返回URL动作"""
# 获取当前记录集(在server action中,records已经包含了选中的记录)
ids = self.ids if self else []
# 构建URL
ids_str = ','.join(str(id) for id in ids) if ids else ''
url = f'/cs_quality/export_excel?ids={ids_str}'
return {
'type': 'ir.actions.act_url',
'url': url,
'target': 'self',
}
5.2 模型方法 - 生成Excel数据
def get_excel_file(self):
"""生成Excel文件并返回二进制数据"""
records = self
# 创建Excel文件
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet('测量数据')
# 定义格式...
# 写入表头...
# 写入数据...
workbook.close()
output.seek(0)
return output.getvalue()
5.3 Controller路由 - 处理文件下载
@http.route('/cs_quality/export_excel', type='http', auth='user', methods=['GET'], csrf=False)
def export_excel(self, ids=None, **kwargs):
"""导出测量数据到Excel"""
# 解析参数
if ids:
ids_list = [int(id.strip()) for id in ids.split(',') if id.strip()]
records = request.env['cs.quality.measurement.data'].browse(ids_list)
else:
records = request.env['cs.quality.measurement.data'].search([])
# 生成Excel
excel_data = records.get_excel_file()
# 生成文件名
filename = f'测量数据导出_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx'
# 返回文件
return request.make_response(
excel_data,
headers=[
('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
('Content-Disposition', content_disposition(filename)),
]
)
六、常见问题与解决方案
6.1 模型外部ID找不到
问题:ValueError: External ID not found in the system: base.model_xxx
解决:显式定义ir.model记录
<record id="model_cs_quality_measurement_data" model="ir.model">
<field name="name">测量数据明细</field>
<field name="model">cs.quality.measurement.data</field>
</record>
6.2 中文文件名乱码
解决:使用content_disposition()函数处理文件名编码
from odoo.http import content_disposition
headers=[
('Content-Disposition', content_disposition(filename)),
]
6.3 日期格式问题
解决:使用write_datetime()方法并指定格式
date_format = workbook.add_format({
'num_format': 'yyyy-mm-dd hh:mm:ss'
})
worksheet.write_datetime(row, col, datetime_value, date_format)
6.4 数字精度问题
解决:使用write_number()方法并指定数字格式
number_format = workbook.add_format({
'num_format': '0.000000' # 保留6位小数
})
worksheet.write_number(row, col, value, number_format)
七、最佳实践
7.1 代码组织
-
模型方法职责分离:
-
action_export_excel(): 负责生成URL动作 -
get_excel_file(): 负责生成Excel二进制数据
-
-
Controller职责:
-
参数解析和验证
-
调用模型方法
-
返回HTTP响应
-
7.2 性能优化
-
内存管理:
-
使用
io.BytesIO()在内存中操作 -
使用
{'in_memory': True}选项 -
及时关闭工作簿释放资源
-
-
大数据量处理:
-
考虑分页导出
-
使用流式写入
-
添加进度提示
-
7.3 错误处理
try:
# Excel生成逻辑
excel_data = records.get_excel_file()
return request.make_response(excel_data, headers=...)
except Exception as e:
_logger.error('导出Excel错误: %s', str(e))
return request.not_found()
7.4 用户体验
-
文件名规范:包含时间戳,避免覆盖
filename = f'测量数据导出_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx' -
格式美化:
-
表头使用醒目的颜色和字体
-
数据使用合适的对齐方式
-
重要信息使用颜色标识(如合格/不合格)
-
-
列宽自适应:
column_widths = [15, 18, 18, 12, ...] for col, width in enumerate(column_widths): worksheet.set_column(col, col, width)
八、扩展功能建议
8.1 导出选项
-
支持选择导出字段
-
支持导出格式选择(Excel/CSV)
-
支持导出模板自定义
8.2 批量导出
-
支持异步导出
-
支持导出任务队列
-
支持导出历史记录
8.3 数据过滤
-
支持按条件过滤导出
-
支持按时间范围导出
-
支持按状态筛选导出
九、总结
9.1 核心技术栈
-
Odoo框架:ir.actions.server, ir.actions.act_url
-
HTTP路由:Controller处理文件下载
-
Excel生成:xlsxwriter库
-
数据流转:模型 → Controller → 文件响应
9.2 关键要点
-
Server Action绑定到列表视图,提供用户入口
-
URL动作跳转到Controller路由
-
Controller解析参数,调用模型方法生成Excel
-
使用xlsxwriter生成格式化的Excel文件
-
通过HTTP响应返回文件供用户下载
9.3 学习价值
-
理解Odoo动作系统(Actions)
-
掌握HTTP Controller的使用
-
学习Excel文件生成技术
-
了解Odoo数据流转机制
适用版本:Odoo 18.0
效果展示

