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

Odoo CSV可下载导出功能异常,求技术排查

Odoo患者报表CSV导出功能故障排查

我在Odoo中开发患者报表导出功能时遇到问题:点击下载按钮后无法生成可下载的CSV文件,触发错误提示(错误核心内容:找不到模型report.patient.wizard的file字段)。

功能预期:用户通过表单选择性别筛选条件,点击下载按钮后生成并下载对应筛选条件的CSV文件。


Transient Model代码

from odoo import models, fields, api, _
from odoo.exceptions import UserError
import io
import csv

class ReportPatientWizard(models.TransientModel):
    _name = "report.patient.wizard"
    _description = "Patient Reports"

    patient_id = fields.Many2one('hospital.patient', string='Patient', readonly=True)
    gender_filter = fields.Selection([('male', 'Male'), ('female', 'Female'), ('other', 'Other')],
                                     string='Gender Filter')

    def _prepare_csv_data(self, patients):
        field_names = ['Name', 'Age', 'Gender']  # Field names for CSV headers
        data = io.StringIO()
        writer = csv.DictWriter(data, fieldnames=field_names)

        writer.writeheader()  # Write CSV header

        for patient in patients:
            row = {
                'Name': patient.name,
                'Age': patient.age,
                'Gender': patient.gender,
                # Add other fields as needed
            }
            writer.writerow(row)

        return data.getvalue()

    @api.multi
    def download_patient_report(self):
        # Ambil data pasien berdasarkan ID yang dipilih
        patient = self.patient_id

        # Filter data berdasarkan gender jika gender_filter dipilih
        if self.gender_filter:
            patients = self.env['hospital.patient'].search([('gender', '=', self.gender_filter)])
        else:
            patients = self.env['hospital.patient'].search([])

        if not patients:
            raise UserError(_('No patients found matching the criteria.'))

        csv_data = self._prepare_csv_data(patients)

        print(f"Records: {patients}")

        # Prepare file name
        filename = f'patient_report_{fields.Date.today()}.csv'

        # Return a response to download the CSV file
        return {
            'type': 'ir.actions.act_url',
            'url': 'web/content/?model=report.patient.wizard&id={}&filename={}&field=file'.format(self.id, filename),
            'target': 'current',
        }

    def print_patient_report(self):
        # Generate and download patient report as CSV
        return self.download_patient_report()

View.xml代码

<record id="report_patient_view" model="ir.ui.view">
    <field name="name">Report Patient</field>
    <field name="model">report.patient.wizard</field>
    <field name="arch" type="xml">
        <form string="Report Patient">
<!--            <field name="patient_id"/>-->
            <group col="1">
<!--                <field name="is_gender"/>-->
                <field name="gender_filter"/>
            </group>
<!--            <field name="journal_ids" required="0" invisible="1"/>-->
            <footer>
                <button name="download_patient_report" string="Download" type="object" class="oe_highlight"/>
                <button string="Cancel" class="btn btn-default" special="cancel"/>
            </footer>
        </form>
    </field>
</record>

<record id="action_report_patient_view" model="ir.actions.act_window">
    <field name="name">Report Patient</field>
    <field name="res_model">report.patient.wizard</field>
    <field name="type">ir.actions.act_window</field>
    <field name="view_mode">form</field>
    <field name="view_id" ref="report_patient_view"/>
    <field name="target">new</field>
</record>

<menuitem id="menu_report"
          name="Report Patients"
          parent="menu_hospital_operations"
          action="action_report_patient_view"
          sequence="15"/>

问题原因及修复方案

核心问题

你返回的ir.actions.act_url试图读取模型的file字段,但你的report.patient.wizard模型中并未定义该字段,这是触发错误的直接原因。同时web/content方式不适合动态生成的临时文件,不符合Odoo导出文件的标准逻辑。

修复步骤

替换原有的下载响应逻辑,改用Odoo标准的二进制文件导出方式:

修改后的download_patient_report方法:

@api.multi
def download_patient_report(self):
    # 筛选患者数据逻辑保留
    if self.gender_filter:
        patients = self.env['hospital.patient'].search([('gender', '=', self.gender_filter)])
    else:
        patients = self.env['hospital.patient'].search([])

    if not patients:
        raise UserError(_('No patients found matching the criteria.'))

    csv_data = self._prepare_csv_data(patients)
    filename = f'patient_report_{fields.Date.today()}.csv'

    # 返回标准二进制文件下载响应
    return {
        'type': 'ir.actions.act_binary',
        'data': csv_data.encode('utf-8'),  # 转换为二进制流
        'filename': filename,
        'mimetype': 'text/csv',
        'target': 'new',
    }

额外优化建议

  1. 删除未使用的patient = self.patient_id变量,清理冗余代码。
  2. 若需解决Excel打开CSV时的中文乱码问题,可修改_prepare_csv_data方法直接生成带BOM的二进制流:
def _prepare_csv_data(self, patients):
    field_names = ['Name', 'Age', 'Gender']
    data = io.BytesIO()
    # 添加UTF-8 BOM解决Excel中文乱码
    data.write(u'\ufeff'.encode('utf-8'))
    writer = csv.DictWriter(data, fieldnames=field_names, encoding='utf-8')
    writer.writeheader()

    for patient in patients:
        row = {
            'Name': patient.name,
            'Age': patient.age,
            'Gender': patient.gender,
        }
        writer.writerow(row)

    data.seek(0)
    return data.read()

此时下载方法中的data参数可直接使用csv_data,无需再编码。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:02:08