今天分享的这个案例属于设计架构上的优化,可提高开发人员的效率,维护系统的统一性和可扩展性。
在业务需求中,将数据导出是一个普遍需求,各部门、各岗位都会需要导出五花八门的各类数据。正常情况下,我们会需要对每一种导出的数据格式报表定义一个向导或方法,常规的方法有如下弊端:
增加了开发人员的工作量,大部分代码是重复的;
不同开发人员导出文件格式不统一,有xls、xlsx、csv、odt等;
团队中开发人员使用的技术实现不一样,有xlwt、openpyxl、pandas等;
需求变化时,难以快速响应(如:需求变更为超过1000条记录,就将附件发邮件,不要显示下载界面;安装了在线表格编辑模块的,报表数据直接在线打开编辑;报表附件发送钉钉接收;)
为了解决这一业务场景面临的问题,我们通过分析这一需求,发现这类需求主要是两部分组成,一个是获取指定条件的数据,二是将数据转换成Excel文档。我们可以把数据到文档这一步做成一个标准化的流程,开发人员只要写一个方法获取需要的数据就可以了。
同时为了方便开发人员调用,我们决定把数据到文档这一步做成一个python的装饰器。大致的思路如下:
先定义一个向导的数据模型和xml
class ExcelExportWizard(models.TransientModel):_name = "excel.export.wizard"file_data = fields.Binary("File")file_name = fields.Char("FileName", size=50)
<record id="excel_export_wizard_view_form" model="ir.ui.view"><field name="name">excel.export.wizard.view.form</field><field name="model">excel.export.wizard</field><field name="arch" type="xml"><form string=""><field name="file_data" readonly="1" filename="file_name"/><field name="file_name" invisible="1"/><footer><button string="Close" class="btn btn-secondary" special="cancel"/></footer></form></field></record>
这个向导主要就是用于提供所有数据导出的下载界面。
二是定义了一个装饰器:
# -*- coding: utf-8 -*-from decorator import decorateimport base64def excelWizard(method):wrapper = decorate(method, _excelExportFromWizard)return wrapperdef _excelExportFromWizard(method, self, fileName):#下面这一段是处理数据转出的逻辑data = method(self)file_data = bytes('\n'.join(['\t'.join(x) for x in data]),encoding='utf-8')#转出在这里结束wizard_model = self.env["excel.export.wizard"]obj = wizard_model.create({"file_data":base64.encodestring(file_data),"file_name":fileName})action = {'name':'数据导出','res_id': obj.id,'res_model': 'excel.export.wizard','view_mode': 'form','type': 'ir.actions.act_window','target':'new',}return action
这个装饰器的作用,就是从被装饰的方法中获取一个数据(二维数组),然后把这个数据处理为需要的格式,再返回导出向导界面。我这里为了简单,就没有写导出Excel的代码,只是简单的把来源数据存为txt文档,你们自己可以在这里根据业务需要作调整。
上面的基本框架做好了,开发人员就比较简单了,如:
@tool.excelWizarddef export_test(self, fileName="人员信息表.txt"):return [[x.name,x.barcode,x.sex] for x in self]
开发人员只要在业务模型中定义一个方法,方法返回一个二维数组,对应excel中的行和列,此方法用我们上面定义的装饰器进行装饰就可以啦。
然后我们在xml中定义这个方法的调用:
<button name='export_test' string='Exp' type='object'/>
用户在点此按钮时,就会提示下图的下载向导:

通过此翻改造设计,实现了以下几点优势:
开发人员工作变简单,只要写数据源获取的代码;
导出格式统一;
用户需求变化时,只要在装饰方法中进行统一修改。




