首页 > 数据库 >Python实战:从数据库到Excel的复杂查询结果处理【下】

Python实战:从数据库到Excel的复杂查询结果处理【下】

时间:2023-12-28 17:34:15浏览次数:54  
标签:style set return 表格 Python 数据库 Excel param se

一、背景描述

上篇中篇,我们已经实现从数据库查询到数据,根据指定条件将处理后的数据写入到excel中,并解决了excel中数据格式异常的问题。而目前生成的excel表格的宽度、表格的样式、字体、单元格背景色等均是默认的,excel结果文件是需要交给运营同学查看的,也就是说表格样式要稍微做下美化。

下面就来介绍使用Python设置excel表格样式

二、步骤讲解

下面是之前生成的excel表格示例:

Python实战:从数据库到Excel的复杂查询结果处理【下】_Python

Step1 创建样式设置基础方法

创建一个ExcelStyle类,方便后续直接继承调用。使用xlwt模块的XFStyle,设置字体、表格边框、表格背景、列宽、对齐方式

注意:这里使用了@staticmethod静态方法装饰器,所以不需要初始化和self参数,只需要通过se=ExcelStyle()来调用就可以了

class ExcelStyle:

    @staticmethod
    def style_head(worksheet, size, wrap=0, is_bg=0, color=22):
        """
        表头的样式
        :param worksheet: 表格
        :param size: 表格列宽
        :param wrap: 1--自动换行,默认不换行
        :param is_bg: 1--设置背景色,默认不设置
        :param color: 默认浅灰色背景
        :return:
        """
        se = ExcelStyle()
        style = se.styles()
        se.set_font(style, height=14)
        se.set_border(style)
        se.set_widths(worksheet, size)
        dicts = {"horz": "CENTER", "vert": "CENTER"}
        se.set_alignments(style, wrap=wrap, **dicts)
        if is_bg == 1:
            se.set_pattern(style, color=color)
        return style

    @staticmethod
    def style_table(dicts: dict):
        """
        普通表格内容样式
        :param dicts: 对齐方式
        :return:
        """
        se = ExcelStyle()
        style = se.styles()
        se.set_font(style, bold=False)
        se.set_border(style)
        se.set_alignments(style, wrap=1, **dicts)
        return style

    @staticmethod
    def styles():
        """设置单元格的样式的基础方法"""
        style = xlwt.XFStyle()
        return style

    @staticmethod
    def set_font(style, bold=True, name='宋体', height=11):
        """
        设置字体,默认宋体加粗,高度11
        :param style:
        :param bold:
        :param name:
        :param height:
        :return:
        """
        style.font.bold = bold
        style.font.name = name
        style.font.height = 20 * height

    @staticmethod
    def set_border(style, status=1):
        """
        设置边框
        :param style:
        :param status:
        :return:
        """
        style.borders.left = status
        style.borders.right = status
        style.borders.top = status
        style.borders.bottom = status

    @staticmethod
    def set_pattern(style, color=23):
        """
        设置表格背景颜色,默认深灰
        0 = 黑, 1 = 白, 2 = 红, 3 = 绿, 4 = 蓝, 5 = 黄, 6 = 品红, 7 = 蓝绿,
        16 = 褐红, 17 = 深绿, 18 = 深蓝, 19 = 棕色, 20 = 暗洋红, 21 = 蓝绿色, 22 = 浅灰, 23 = 深灰......
        :param style:
        :param color:
        :return:
        """
        style.pattern.pattern = xlwt.Pattern.SOLID_PATTERN
        style.pattern.pattern_fore_colour = color

    @staticmethod
    def set_widths(worksheet, size):
        """
        设置宽度
        :param worksheet:
        :param size:
        :return:
        """
        for i, v in enumerate(size):
            worksheet.col(i).width = v * 256

    @staticmethod
    def set_alignments(style, wrap=1, **kwargs):
        """
        设置对齐方式,默认自动换行
        中心对齐参数:{"horz": "CENTER", "vert": "CENTER"}
        horz(水平):CENTER(居中),DISTRIBUTED(两端),GENERAL,CENTER_ACROSS_SEL(分散),RIGHT(右),LEFT(左)
        vert(垂直):CENTER(居中),DISTRIBUTED(两端),BOTTOM(下),TOP(上)
        """

        if "horz" in kwargs.keys():
            style.alignment.horz = eval(f"xlwt.Alignment.HORZ_{kwargs['horz'].upper()}")
        if "vert" in kwargs.keys():
            style.alignment.vert = eval(f"xlwt.Alignment.VERT_{kwargs['vert'].upper()}")
        style.alignment.wrap = wrap  # 设置自动换行

Step2 创建表格样式模板

表头样式模板

注意:需要定义表头每一列的宽度,也就是说size参数是个列表

@staticmethod
def style_head(worksheet, size, wrap=0, is_bg=0, color=22):
    """
    表头的样式
    :param worksheet: 表格
    :param size: 表格列宽
    :param wrap: 1--自动换行,默认不换行
    :param is_bg: 1--设置背景色,默认不设置
    :param color: 默认浅灰色背景
    :return:
    """
    se = ExcelStyle()
    style = se.styles()
    se.set_font(style, height=14)
    se.set_border(style)
    se.set_widths(worksheet, size)
    dicts = {"horz": "CENTER", "vert": "CENTER"}
    se.set_alignments(style, wrap=wrap, **dicts)
    if is_bg == 1:
        se.set_pattern(style, color=color)
    return style

表格内容样式模板

已经设置过表头的列宽了,表格内容就不需要再设置了

@staticmethod
def style_table(dicts: dict):
    """
    普通表格内容样式
    :param dicts: 对齐方式
    :return:
    """
    se = ExcelStyle()
    style = se.styles()
    se.set_font(style, bold=False)
    se.set_border(style)
    se.set_alignments(style, wrap=1, **dicts)
    return style

Step3 应用表格样式模板

将原始代码封装成了一个类,直接继承ExcelStyle类,先定义表头和表格内容的样式,然后在写入表格内容时传入对应的样式即可

定义表格样式

se = QueryToExcel()

# 定义表头样式
size = [20, 20, 12, 12, 20, 12, 12, 12, 12, 12, 12]  # 表头列宽列表
head_style = se.style_head(sheet, size, wrap=1, is_bg=1)  # 定义表头样式
# 定义表格内容样式
normal_style = se.style_table({"horz": "CENTER", "vert": "CENTER"})  # 表格内容样式

传入表格样式

# 【写入表头】
for col, val in enumerate(headers):
    sheet.write(0, col, val, head_style)  
#------------------------------略------------------------------  

#【写入表格内容】
r2_k_list = [key for key in results2[0]]
new_val = convert_value(results2[0][r2_k_list[0]])
sheet.write(i + 1, 10, new_val, normal_style)
#------------------------------略------------------------------ 
sheet.write(i + 1, col, '是', normal_style)

Step4 运行效果展示

这下表格好看多了,可直接发给运营小姐姐同学看啦

Python实战:从数据库到Excel的复杂查询结果处理【下】_表格样式_02

三、总结分析

1.通过创建ExcelStyle类来设置表格样式,便于继承调用

2.创建设置表格样式的基础方法,可设置常见的excel表格样式

3.创建表头和表格的样式模板,在xlwt.write写入excel内容时传入样式即可

4.封装了查询数据库和写入excel的基础代码

完整代码:

import datetime
import time
import pymysql
import xlwt


class ExcelStyle:

    @staticmethod
    def style_head(worksheet, size, wrap=0, is_bg=0, color=22):
        """
        表头的样式
        :param worksheet: 表格
        :param size: 表格列宽
        :param wrap: 1--自动换行,默认不换行
        :param is_bg: 1--设置背景色,默认不设置
        :param color: 默认浅灰色背景
        :return:
        """
        se = ExcelStyle()
        style = se.styles()
        se.set_font(style, height=14)
        se.set_border(style)
        se.set_widths(worksheet, size)
        dicts = {"horz": "CENTER", "vert": "CENTER"}
        se.set_alignments(style, wrap=wrap, **dicts)
        if is_bg == 1:
            se.set_pattern(style, color=color)
        return style

    @staticmethod
    def style_table(dicts: dict):
        """
        普通表格内容样式
        :param dicts: 对齐方式
        :return:
        """
        se = ExcelStyle()
        style = se.styles()
        se.set_font(style, bold=False)
        se.set_border(style)
        se.set_alignments(style, wrap=1, **dicts)
        return style

    @staticmethod
    def styles():
        """设置单元格的样式的基础方法"""
        style = xlwt.XFStyle()
        return style

    @staticmethod
    def set_font(style, bold=True, name='宋体', height=11):
        """
        设置字体,默认宋体加粗,高度11
        :param style:
        :param bold:
        :param name:
        :param height:
        :return:
        """
        style.font.bold = bold
        style.font.name = name
        style.font.height = 20 * height

    @staticmethod
    def set_border(style, status=1):
        """
        设置边框
        :param style:
        :param status:
        :return:
        """
        style.borders.left = status
        style.borders.right = status
        style.borders.top = status
        style.borders.bottom = status

    @staticmethod
    def set_pattern(style, color=23):
        """
        设置表格背景颜色,默认深灰
        0 = 黑, 1 = 白, 2 = 红, 3 = 绿, 4 = 蓝, 5 = 黄, 6 = 品红, 7 = 蓝绿,
        16 = 褐红, 17 = 深绿, 18 = 深蓝, 19 = 棕色, 20 = 暗洋红, 21 = 蓝绿色, 22 = 浅灰, 23 = 深灰......
        :param style:
        :param color:
        :return:
        """
        style.pattern.pattern = xlwt.Pattern.SOLID_PATTERN
        style.pattern.pattern_fore_colour = color

    @staticmethod
    def set_widths(worksheet, size):
        """
        设置宽度
        :param worksheet:
        :param size:
        :return:
        """
        for i, v in enumerate(size):
            worksheet.col(i).width = v * 256

    @staticmethod
    def set_alignments(style, wrap=1, **kwargs):
        """
        设置对齐方式,默认自动换行
        中心对齐参数:{"horz": "CENTER", "vert": "CENTER"}
        horz(水平):CENTER(居中),DISTRIBUTED(两端),GENERAL,CENTER_ACROSS_SEL(分散),RIGHT(右),LEFT(左)
        vert(垂直):CENTER(居中),DISTRIBUTED(两端),BOTTOM(下),TOP(上)
        """

        if "horz" in kwargs.keys():
            style.alignment.horz = eval(f"xlwt.Alignment.HORZ_{kwargs['horz'].upper()}")
        if "vert" in kwargs.keys():
            style.alignment.vert = eval(f"xlwt.Alignment.VERT_{kwargs['vert'].upper()}")
        style.alignment.wrap = wrap  # 设置自动换行


class QueryToExcel(ExcelStyle):

    @staticmethod
    def to_excel(dbinfo, file):
        se = QueryToExcel()
        # 定义表头
        headers = ['主业务id', '次业务id', '会员id', '是否完成', '进入时间', '分值', '是否重复操作', '重复操作次数', '是否首次操作', '失败次数', '总时长']
        # 新建工作簿和工作表
        book = xlwt.Workbook(encoding='utf-8')  # 新建工作簿
        sheet = book.add_sheet("new_sheet", cell_overwrite_ok=True)  # 新建sheet

        # 定义表头样式
        size = [20, 20, 12, 12, 20, 12, 12, 12, 12, 12, 12]  # 表头列宽列表
        head_style = se.style_head(sheet, size, wrap=1, is_bg=1)  # 定义表头样式
        # 定义表格内容样式
        normal_style = se.style_table({"horz": "CENTER", "vert": "CENTER"})  # 表格内容样式

        # 写入表头
        for col, val in enumerate(headers):
            sheet.write(0, col, val, head_style)

        # 查询表1的数据
        a_ids = "1977****144,1748****456"
        sql1 = f"select * from table1 where a_id in ({a_ids}) and m_id={100001}"
        results1 = select_from_mysql(dbinfo, sql1)

        # 根据表1查询结果查询并组装表2的数据
        if results1 is not None:
            for i, v in enumerate(results1):
                r1_k_list = [key for key in v]
                for col, k in enumerate(v):
                    if col == 1:
                        new_val = convert_value(v[r1_k_list[col]])
                        sheet.write(i + 1, col, new_val, normal_style)
                        # 查询表2的数据
                        sql2 = f"select * from table2 where a_id={v[r1_k_list[0]]} and mi_id={v[r1_k_list[col]]} and m_id={100001}"
                        results2 = select_from_mysql(dbinfo, sql2)
                        if results2 != ():
                            r2_k_list = [key for key in results2[0]]
                            new_val = convert_value(results2[0][r2_k_list[0]])
                            sheet.write(i + 1, 10, new_val, normal_style)
                        else:
                            sheet.write(i + 1, 10, '', normal_style)
                    elif col in [3, 6]:
                        if convert_value(v[r1_k_list[col]]) == '1':
                            sheet.write(i + 1, col, '是', normal_style)
                        else:
                            sheet.write(i + 1, col, '否', normal_style)
                    elif col == 8:
                        if convert_value(v[r1_k_list[3]]) == '1' and convert_value(v[r1_k_list[col]]) == '0':
                            sheet.write(i + 1, col, '是', normal_style)
                        else:
                            sheet.write(i + 1, col, '否', normal_style)
                    else:
                        sheet.write(i + 1, col, convert_value(v[r1_k_list[col]]), normal_style)
        # 保存excel
        book.save(f"{file}.xlsx")


def is_date(val):
    """
    判断date_str是否为日期格式
    """
    date_format = "%Y-%m-%d"
    try:
        if isinstance(val, str):
            new_str = val[:10]
            valid_date = time.strptime(new_str, date_format)
            return True
        else:
            return False
    except ValueError or TypeError as e:
        return False


def convert_value(val):
    """转换数据格式为excel"""
    if isinstance(val, bytes):
        val = ord(val)
    if is_date(val):
        val = datetime.datetime.strptime(val, "%Y-%m-%d %H:%M:%S.%f")
    new_val = str(val)
    return new_val


def select_from_mysql(dbinfo, sql):
    """
    连接数据库执行sql
    """
    conn = pymysql.connect(**dbinfo)
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return results


if __name__ == "__main__":
    # 数据库信息
    db_info = {
        'host': "192.168.1.1",
        'port': 3306,
        'user': "test",
        'passwd': "test",
        'db': "test_db",
        'charset': "utf8"
    }
    file_name = 'target'
    QueryToExcel().to_excel(db_info, file_name)


标签:style,set,return,表格,Python,数据库,Excel,param,se
From: https://blog.51cto.com/u_16379005/9017040

相关文章

  • 【python机器学习课程设计】驾驶员睡意检测——机器模型训练
    一.选题背景  驾驶员的疲劳和睡意是道路交通安全的重要隐患之一。据统计,疲劳驾驶导致的交通事故占比较高,甚至可能造成生命和财产的巨大损失。因此,开发一种有效的驾驶员睡意检测系统对于提高交通安全具有重要意义。  通过监测驾驶员的眼部数据等,可以建立一个机器学习模型来......
  • Python - 输出一个最简单的log
    输出一个最简单的log点击查看代码importlogging#创建logger对象logger=logging.getLogger(__name__)logger.setLevel(logging.DEBUG)#log等级总开关#log输出格式formatter=logging.Formatter("%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:......
  • 【Lidar】Open3D点云K-Means聚类算法:基于距离的点云聚类(单木分割)附Python代码
    ​ 1K-Means算法介绍        K-means聚类算法是一种无监督学习算法,主要用于数据聚类。该算法的主要目标是找到一个数据点的划分,使得每个数据点与其所在簇的质心(即该簇所有数据点的均值)之间的平方距离之和最小。        在K-means聚类算法中,首先需要预定义簇......
  • Python random模块(获取随机数)常用方法和使用例子
    random.randomrandom.random()用于生成一个0到1的随机符点数:0<=n<1.0random.uniformrandom.uniform(a,b),用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限。如果a>b,则生成的随机数n:a<=n<=b。如果a<b,则b<=n<=a代码如下:print(ra......
  • Python中__init_subclass__特殊方法
    __init_subclass__是Python3.6引入的一个特殊方法,用于在子类被定义时执行一些操作。这个方法允许你在父类中定义一个类方法,当子类继承父类时会自动调用这个方法,你可以在其中进行一些初始化工作。以下是关于__init_subclass__方法的一些重要点:目的:__init_subclass__方......
  • python生成器generator的用法
    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否......
  • python中的泛型使用TypeVar
    1.引入为什么需要TypeVarPEP484的作者希望借助typing模块引入类型提示,不改动语言的其它部分。通过精巧的元编程技术,让类支持[]运算不成问题。但是方括号内的T变量必须在某处定义,否则要大范围改动python解释器才能让泛型支持特殊的[]表示法。鉴于此,我们增加了typing.TypeVar构造......
  • python 四数之和 多种解法
    方法一:暴力枚举暴力枚举方法比较容易想到,就是将四个数的组合进行遍历,找到符合要求的组合。代码如下:deffourSum(nums,target):length=len(nums)nums.sort()result=[]foriinrange(length-3):forjinrange(i+1,length-2):......
  • `pip` 和 `pip3` 是 Python 的包管理工具,它们可以用来查找、下载、安装和卸载 Python
    `pip`和`pip3`是Python的包管理工具,它们可以用来查找、下载、安装和卸载Python包¹。这两个命令的区别主要取决于你的系统中安装的Python版本¹³⁴⁵:-如果你的系统中只安装了Python2,那么只有`pip`可以使用³。-如果你的系统中只安装了Python3,那么`pip`和`pi......
  • 羽毛球比赛python
    importrandomimportosprint("2班17向悦")#介绍比赛以及程序defprint_introduce():print("Thisisabadmintongamesimulationprogram")print("Theprogramrequirestwoplayers'abilityvalues(expressedindecimalsfrom0to1)&q......