• 【QuotationTool的代码实现】framework部分


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

    本章主要介绍framework的功能实现

    之前我们讲到,framework其实存放的是所有可以复用的代码,包括

    • 调用第三方库读写Excel

    • 对log工具的改进包

    • 对MySQL的操纵包

    代码结构

    我们先来看一下代码结构

    image.png

    功能函数

    function,includeList.py,pc.py都属于功能函数,也就是基本上每个项目里面都会有他们

    function.py

    function.py其实主要是为了M、V、C调用起来更为方便。

    我们希望M、V、C这三种类型的代码命名更为规范,比如

    • 业务模块M,我们希望它命名为类似“xxxxModelClass”这样,也就是“功能+Model+Class”这样。

    • 控制模块C,我们希望它类似"xxxxControllerClass"这样,把Controller带上

    • 视图模块V,我们也希望它能带上"xxxViewClass"字样

    既然这三者都这么规范了,我们何不使用一个统一的函数来调用了,这样更为简单 。

    于是对于Model的调用为,具体代码可参考python模块&类的导入

    其实就是根据字符串动态的导入相应的模块,最后进行实例化

    # name:字符
    # 作用:初始化Model
    def M(name):
        libs = __import__('libs.Model.'+name+'ModelClass');#动态的导入
        model = getattr(libs , "Model");#通过反射一步一步获得模块"xxxModelClass"
        testModelClass= getattr(model , name+'ModelClass');
        testModel = getattr( testModelClass, name+"Model");#通过反射获得类testModel
        return testModel();#实例化
    

    那么调用方法呢?
    比如

    rehandleInstance = M("rehandle");
    

    实际上它就是首先将libs.Model.rehandleModelClass这个模块加载进去了,然后调用rehandleModelClass()来进行实例化,赋给rehandleInstance

    对于View和Controller的实例化代码也类似。
    image.png

    includeList.py

    includeList.py把framework里面所有自定义的模块的加载语句都列出来。

    这样的好处就是,我在其他地方只需要加载includeList.py就可把framework里面的所有模块加载进来

    from  framework.includeList import  *
    

    includeList.py的详细代码:

    # !/usr/bin/env python3
    #encoding:UTF8
    # 将自定义的库加入
    from framework.libs.config.configParserClass   import *
    from framework.libs.excel.XlsReaderClass       import *
    from framework.libs.logutil.LogUtilsClass      import *
    from framework.libs.view.XlsWriterClass        import *
    from framework.libs.db.MySQLClass  import *
    from  framework.function.function import *
    
    

    pc.py

    pc.py的主要功能是提供一个对外调用的接口。

    我们可以在admin.py里面调用

    method = getParser("controller","method");
    pc.run("quotation",method);
    

    第1句指的是从配置文件里面读method方法是什么。

    然后调用pc.py中的run函数,把要执行的controller和method同时传递进去。

    也就是调用quotaitonControllerClass中的method方法。

    具体实现:

    # !/usr/bin/env python3
    #encoding:UTF8
    import os.path
    import os
    from  framework.includeList import  *
    
    
    def run(controller,method):
        C(controller,method);
        # C("quotation","index");
    
    

    image.png

    自定义函数

    在framework/libs里面存放的都是自定义函数。

    config/configParserClass.py

    configParserClass.py的作用是解析configure.conf文件的。

    如下为configure.conf中的一段代码

    [section]
    key=value
    

    其中 [section]称为域,可以将这个configure.conf文件划分成若干个逻辑上的模块,

    key=value本质上就是一个键值对。

    所以这个解析函数就是首先找到某个,然后去这个域里面通过key读取里面的value

    需要注意的是:

    configure.conf文件中不能存在两个相同的section和key

    那调用方法是就是

    getParser("section","key")
    

    第一个参数是section,第二个参数就是要取的key

    那么编写代码:

    #获取config配置文件
    # 配置文件格式
    # [section]
    # key=value
    def getParser (section, key):
        try:
            config = configparser.ConfigParser();
            # # 路径:当前文件上两层
            # os.path.dirname(__file__):获取当前文件的路径
            path = os.path.join(os.path.dirname(os.path.dirname (os.path.dirname(os.path.dirname(__file__)))),'configure.conf') ;
            # 文件格式:UTF-8
            config.read(path , 'UTF-8');
            
            value = config.get(section,key)
        except Exception as data:
            print("configure文件中存在两个相同的section"+str(data))
        return value
    

    代码的含义为,先找到configure.conf存放的路径,然后读取它,最后使用get函数来获得key对应的value值。

    logutil/LogUtilsClass.py

    我们平时要打印信息,可能最常用的就是print()函数了,但是在工程里面使用这个函数,多有不便。

    它最大的问题在于不能对信息分级

    怎么理解?

    比如说有些信息是错误信息,我应该在任何时候都显示,有些信息只是调试中用到信息,我希望在上线以后就关闭它,有些信息是为了给客户看的,作为一个提示。

    但是在python中就一个print()函数,无法很好的控制什么时候让它显示呢。

    所以我们可以定义4种信息打印级别:

    • DEBUG:表示调试信息

    • INFO:给用户展示的信息

    • ERROR:错误信息

    • NOTHING:啥都不显示

    DEBUG = 0;
    INFO = 1;
    ERROR = 2;
    NOTHING =3 ;
    

    设定当前的级别为level,我们可以从配置文件中读取

    level=int(getParser("loglevel","level"))
    

    如果当前的level为3,说明它处于NOTHING状态,其他信息当然不显示。

    也就是DEBUG,INFO,ERROR等信息只有在它大于level级别的时候才显示
    所以

        
    def debug(msg):
        if (DEBUG >= level):
            print(msg);
    
    def info (msg):
        if(INFO >= level):
            print(msg);
    
    def error (msg):
        if (ERROR >= level):
            print(msg);
    

    那么在打印信息的时候,如果此时我们想打印一个debug信息就可以

    debug("debug信息")
    

    当level设置为INFO的时候,因为level > DEBUG,所以不会显示。

    也就是说

    在开发的时候,我们可以把调试信息用debug()打印,level = DEBUG,此时正常输出。

    上线以后,我们把level级别设置为更高一级的,debug信息就不会打印了。

    excel/XlsReaderClass.py

    XlsReaderClass.py是使用xlrd模块进行Excel读取的。

    这个模块的具体使用方法可见:【python】python读excel-xlrd

    数据结构

    那么我们希望读出来的数据是这个什么样子呢?也就是数据结构是怎么样的?

    既然Excel是个二维表格,那么读出来的数也放在一个二维表格里面得了。

    产品编码 产品型号 数量 标准价(RMB)
    0235A0W2 RT-MSR5660 2 50000

    这样的缺点在于:取每个元素,需要计算index,不方便编程。

    比如我们要取第三行的“RT-MSR5660”,我们需要使用a[1][1]来取,非常不方便。

    我们知道最方便取的数据结构为dict,只要传进去一个key,它就会返回一个value,这样的好处是

    • 可以为每一列赋予实际的含义,比如说可以把产品型号的key设为BOM,我们要取“RT-MSR5660”的时候,就可以用a[1]['BOM']

    • 如果要调换列的顺序,可以轻松做到,更为的灵活

      因为每一列赋予了实际的含义,我们根本不用担心具体的顺序

    那么具体的数据格式应该是怎么样的呢?

    [
    {"BOM":"产品编码",    
    "typeID":"产品型号",    
    "description":"项目名称",    
    "totalQuantity":"数量",    
    "unitsNetListPrice":"标准价(RMB)"},
    
    {"BOM":"0235A0W2",    
    "typeID":"RT-MSR5660",   
    "description":"H3C MSR 56-60路由器机框",   
    "totalQuantity":"2",    
    "unitsNetListPrice":"50000"}
    ]
    
    • 原始表格中的每一行为一个dict

    • 所有行组成一个list

    从Excel中读数据

    既然现在数据结构已经设计好了,我们就来看如何读数据,并形成这样的数据结构吧。

    首先引入模块

    import xlrd
    

    然后定义一个操作类

    class XlrdTool(XlsReader):
        # 作用:获取关联数组
        # inputHeaderKey:数组每一列的对应的键值
        # 返回:一个数组,数组的每一行为一个dict,代表原来表格里面的每一行,其中此dict的键名为输入的inputHeaderKey,键值为读入的excel文件的对应值。
        
        def getAssociativeArray (self, excelPathName, sheetName , inputHeaderKey):
            list = []
            try:
                sheetList = xlrd.open_workbook(excelPathName).sheet_by_name(sheetName);
                # row:表示从当前sheet读出了的每一行,
                # 将每一行的row_values与inputHeaderKey组成dict
                list = [dict (zip (inputHeaderKey , sheetList
                .row_values(row))) for row in range(sheetList.nrows)];
                
            except Exception as data:
                print("打开文件失败,%s" % data);
            return list;
    

    里面最关键的代码其实只有:

    list = []
     sheetList = xlrd.open_workbook(excelPathName).sheet_by_name(sheetName);
     list = [dict (zip (inputHeaderKey , sheetList
                .row_values(row))) for row in range(sheetList.nrows)];
    

    我们来一一看看。

    • 从Excel中的某个sheet里面读出数据,xlrd.open_workbook(excelPathName).sheet_by_name(sheetName)

    • [dict (zip (inputHeaderKey , sheetList .row_values(row))) for row in range(sheetList.nrows)];我们可以拆解一下:

      • 这是一个列表生成式,for row in range(sheetList.nrows)表示对读出来的数组的每一行 row 进行遍历,

      对其中某一行row

      • 首先使用xlrd中的函数row_values取出每一行的值

      • inputHeaderKey表示为每一列赋予的一个key,它是一个数组。

      • 然后使用zip把读出来的每一行与inputHeaderKey组成键值对,再在外面迁套dict形成一个字典。
        也就是

    {"BOM":"0235A0W2",    
    "typeID":"RT-MSR5660",   
    "description":"H3C MSR 56-60路由器机框",   
    "totalQuantity":"2",    
    "unitsNetListPrice":"50000"}
    
    • 所有的dict形成一个列表
  • 相关阅读:
    基于矩阵式产品管理的奖金如何发放?
    再谈技术开发项目与产品开发项目的差异
    如何培养合格的产品经理?
    技术规划变革管理——共创力典型咨询案例
    研发人员任职资格管理深圳公开课成功举办!
    深圳市共创力《产品需求挖掘和规划》深圳公开课!(2019.12.6~7)
    技术规划与路标开发实践公开课在深圳成功举办!
    产品路标开发是企业持续成功的关键路径
    什么是技术规划(TPP)?
    什么是测试系统工程师(TSE)?
  • 原文地址:https://www.cnblogs.com/dy2903/p/8465920.html
Copyright © 2020-2023  润新知