【QuotationTool】Model的实现(一),获得Excel路径以及Excel输出格式

项目链接:https://gitee.com/xyjtysk/quotationTools

【QuotationTool的代码实现】主要数据结构.md中,我们介绍了如何针对的本项目的主要数据结构是什么,也就是把Excel表格里面的数据读出来,放到什么样的结构里面方便后续的处理。

下面我们接着介绍如何实现明细清单页

要实现完成的流程,我们首先得获得Excel所在的完整路径+文件名,以及对输出的表格有那些列进行限定。

获得输入Excel路径

outputfileModelClass.py就是用来获得输入的Excel表格路径以及文件名的。

路径名可以通过配置文件设定,而文件名的话,需要遍历当前路径,从中找出Excel文件。

  • 获得路径

    首先我们在configure.conf里面设定inputfilePath和outputfilePath

# #*****************文件路径的配置*****************
[path]
# inputfilePath=project
inputfilePath=
# inputfilePath=input
outputfilePath=project

然后使用getParser进行解析,获得inputfilePath的具体值。

为了程序的可移值性,我们希望使用相对路径

那在python中怎么使用相对路径呢?
可以

filePath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,filePath)

使用os.path.dirname(__file__)获得这个py文件的当前路径,然后往上翻两层即可到达主目录。

  • 遍历下面的所有文件, 找出Excel格式的文件。
files = [file for file in os.listdir(filePath) if file.rpartition('.')[2] == 'xls' or file.rpartition('.')[2]=='xlsx'];

这是一个列表生成式,大意是使用os.listdir(filePath)列出所有的文件,然后找后缀名为"xls"或者"xlsx"的。

  • 有一个就直接选中
        elif len(files) == 1:
            fileSelected = files[0];
如果有多个Excel文件怎么办?我们可以将输出的文件名尾巴上添一个数字,每运行一次,这个数字就+1,所以找尾号数字最大的就可以了。

这就要求,**我们在同一个目录里面最多只能放同一个Excel运行出来的文档。**
max  = -1;
# 存放选中的文件名
fileSelected = ""
try:
    for file in files :
        # 去掉后缀,并且依照"-"分割为数组
        fileSplitList = file.rpartition('.')[0].split('_');
        # 此时如果后缀编号是8位,表明是从NHCT导出的,不选
        if len(fileSplitList[-1] ) == 8:
            max = -1;
        # 如果倒数第一位比max还大,则更新
        elif int(fileSplitList[-1]) > max:
            max = int(fileSplitList[-1]);
            fileSelected = file;

就是经典的找max的算法。
image.png

获得输出Excel路径

在上一章我们获得输入Excel的路径以及文件名,本章要获得输出的Excel完整路径,对应的文件为outputfileModelClass.py

之前已经说过,我们对同一个文档运行多次程序,每次的尾号要+1.

class outputfileModel(object):
    
    def getOutputFile(self,file):
        fileSplitList = file.rpartition('.')[0].split('_');
        pattern = getParser('inOutmode','outputMode');
        suffix = 0;
        if len(fileSplitList[-1]) >= 3 :
            suffix = 1;
        else:
            try :
                suffix = int(fileSplitList[-1]) + 1;
            except Exception as data: 
                print ("文件名不对"%data);
            
        return fileSplitList[0] + "_" + pattern + "_" + str(suffix)+".xls";
        
  • 首先对文件名使用"_"进行分割,切分成数组。

  • 对数组的倒数第一位进行判断,如果是位数大于3(NHCT导出来的后缀都是日期,比如20180221,位数一定大于3),则将后缀设为1.

  • 其他的后缀依次加一即可。

获得输入和输出的列的key

本功能由parameterModelClass.py实现。

我们可以对输入输出的列对应的key进行设定,这样就可以自由的操纵哪些列输出,哪些列不输出了。

输入有哪些列需要和读入的Excel想匹配,如果不匹配的话,可能程序就会报错。

按照场景分类

我们可以归纳一下常用的几种表格模式:

  • 给内部使用的,特点是有目录价

  • 发给客户的,这就没有目录价了。

  • 还有就是招商银行、平安科技投标

其实输入的文档一般都是从NHCT导出来的Excel,或者说经过脚本处理过的格式。他们的区别在于,脚本处理过的Excel多了一个单套数量。

image.png

那么我们使用哪种数据结构来表示每一列对应的key呢?
可以选用数组,也可以使用dict

使用dict的好处在于,更为直观,如下

exportInput = {
    "ID":"ID",
    "BOM":"产品编码",
    "typeID":"产品型号",
    "description":"项目名称",
    "quantity":"单套数量",
    "unitsNetListPrice":"目录价",
    "discount":"折扣",
    "unitsNetPrice":"单价",
    "totalPrice":"总价",
    "totalListPrice":"总目录价",
    "remarks":"备注",
    "PL":"产线"
    # "waston":"WATSON_LINE_ITEM_ID",
}

它表示从NHCT导出来的表格的列的含义。

同理可以得到脚本运行的出来的列


internalInput = {
    "ID":"ID",
    "BOM":"产品编码",
    "typeID":"产品型号",
    "description":"项目名称",
    "quantity":"单套数量",
    "totalQuantity":"总数量",
    "unitsNetListPrice":"目录价",
    "discount":"折扣",
    "unitsNetPrice":"单价",
    "totalPrice":"总价",
    "remarks":"备注"
}

同样的道理,输出的列为


internalOutput = {
    "ID":"ID",
    "BOM":"产品编码",
    "typeID":"产品型号",
    "description":"项目名称",
    "quantity":"单套数量",
    "totalQuantity":"总数量",
    "unitsNetListPrice":"目录价",
    "discount":"折扣",
    "unitsNetPrice":"单价",
    "totalPrice":"总价",
    "remarks":"备注"

}

image.png

把变量单独拆分

输入哪些列,输出哪些列,我们可能会经常修改,所以单独把要经常变的变量剥离出来,单独放在inputVariable.py里面,这样就实现了配置和代码分离。

大家可以仔细观察一下上一小节提到的变量名,internalInputexportInput,末尾都带了Input

这样,我们只需要把前缀与"input"联接在一起,就可以取出这个变量了。

读入输入输出的键值

最后我们只要使用函数把inputVariable.py的变量读入即可,可见parameterModelClass.py

  • 首先在配置文件里面设定输入和输出的模式
[inOutmode]
# 输入输出pattern
inputMode=internal
outputMode=internal

使用getParser读出来

        inputPattern = getParser('inOutmode','inputMode');
        info("输入的模式是"+str(inputPattern))
        outputPattern = getParser('inOutmode','outputMode');
        info("输出的模式是"+str(outputPattern))
  • 输入变量可以使用inputPattern+ "Input"获得,输出变量可以使用outputPattern + "Output"获得。

    然后就是动态的把inputVariable.py加载进来即可。

var = __import__("libs.inputVariable")
inputvar = getattr(var,"inputVariable")

inputParam = getattr(inputvar, (inputPattern+ "Input"));

outputParam = getattr(inputvar, (outputPattern + "Output"));

至此准备工作就做完了,下面就可以开始读Excel了。

image.png

在Controller中调用

下面我们可以看看之前的几个Model是如何在Controller中进行调度的。

var = __import__("libs.inputVariable")
inputvar = getattr(var,"inputVariable")        
inputFile = M("file").getProjectName();
outputFile = M("outputfile").getOutputFile(inputFile);
info("打开的文件是" + inputFile);
# 获得输入和输出的keys
[inputParam , outputParam] = M("parameter").getParameter(inputFile);
# 以quotationTools的根目录作为基准
basepath = os.path.dirname(os.path.dirname(os.path.dirname(__file__)));
inputPath = os.path.join(basepath,getParser('path','inputfilePath'),inputFile);
outputPath = os.path.join(basepath,getParser('path','outputfilePath'),outputFile);
# 主sheetName
sheetName = '价格明细清单';
原文地址:https://www.cnblogs.com/dy2903/p/8466816.html