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', }
额外优化建议
- 删除未使用的
patient = self.patient_id变量,清理冗余代码。 - 若需解决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
相关产品推荐
相关产品推荐

