zoukankan      html  css  js  c++  java
  • 【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 = '价格明细清单';
    
  • 相关阅读:
    (二)微信开发工具
    (一)微信小程序环境搭建
    mysql安装--window版
    (六--二)scrapy框架之持久化操作
    windows安装redis
    (六--一)scrapy框架简介和基础应用
    (五)selenuim和phantonJs处理网页动态加载数据的爬取
    (四)requests模块的cookies和代理操作
    (三)三种数据解析方式学习
    (二)requests模块
  • 原文地址:https://www.cnblogs.com/dy2903/p/8466816.html
Copyright © 2011-2022 走看看