【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形成一个列表
posted @ 2018-02-24 15:12  dy2903  阅读(176)  评论(0编辑  收藏  举报