Python-使用xlsxwriter创建单元格下拉列表(数据校验)

news/2024/10/22 12:30:56/

在一个B/S系统中,用户经常需要从以Excel的方式填写后导入,此时网页上需要提供Excel填写的模板,将所需填写的字段以及所处的列的位置固定下来。其中,避免用户随意填写导致系统后台校验出错,对于某些字段,系统需要预设好固定的选项值,用户只能在给定的范围内选择,不允许人工输入填写。

如果字段值的数据范围长期不变,则可直接固化在Excel中;如果字段值偶尔会更新,需要在下载Excel模板时,实时从数据库获取,则需要动态生成该Excel模板。

静态Excel模板

制作Excel模板

新建Excel文件,设置好表头名称,从第二行开始设置数据校验。具体步骤为:

数据》数据验证》设置,“允许”选择“序列”,“来源”字段可手动输入文本(以英文逗号分隔)或选中任意sheet的任意表格内容。

提供下载

from flask import current_app, request, send_from_directory, send_filedef download_excel_template():"""下载Excel模板"""file_dir = os.path.join(current_app.config['LIB_DIR'], 'files', 'templates')  # 模板存放目录current_app.logger.info("下载%s下的文件:%s" % (file_dir, 'Template.xlsx'))return send_from_directory(file_dir, 'Template.xlsx', as_attachment=True)

动态Excel模板

更特殊的场景下,Excel单元格下拉列表的内容需要从系统中动态获取。例如,用户希望通过填写并上传Excel到某系统,由系统在openstack平台上创建一台虚拟机。虚机的hostname、ip等内容需要由用户自行指定,但虚机所使用的Flavor(即CPU/内存)、镜像(image)、卷的类型(volume type)、网络(network)、子网(subnet)等,名称较为复杂不便记忆,最好是能提供Excel的下拉选择功能。image等信息需要从openstack平台拉取,且管理员随时都有可能会在openstack平台上进行增删改的操作,因此为保持Excel模板的准确性、避免经常性的更新维护,可以动态Excel模板的方式提供下载。

这里,推荐使用xlsxwriter模块生成Excel文件。[Creating Excel files with Python and XlsxWriter — XlsxWriter Documentation]

确定Excel的列名

header_row = ['hostname', 'flavor', 'image']

获取下拉选项数据

flavors = get_openstack_flavor_names()
images = get_openstack_image_names()

列表直接写在文本中

通用函数

# chr(i)  65-90   # A,B,C ... Zdef get_column(idx):"""根据数字序号,获取Excel的列名,从0开始例如,0->A"""prefix = int(idx/26)suffix = idx%26if not prefix:return chr(suffix+65)else:return get_column(prefix)+chr(suffix+65)def get_excel_cell_name(row_idx, col_idx):"""根据行列的序号,获取单元格的名称,从(0,0)开始例如,(0,0)->A1"""if row_idx < 0:raise ValueError("Excel的行号必须大于等于0")if col_idx < 0:raise ValueError("Excel的列号必须大于等于0")return "%s%s"%(get_column(col_idx), row_idx+1)

生成Excel

对于单元格的数据校验,可以使用其data_validation功能。Working with Data Validation — XlsxWriter Documentation

import xlsxwriter
from flask import current_appdef generate_excel_template():newfile = os.path.join(current_app.config['TMP_DIR'], 'download', 'Template-%s.xlsx' % (time.strftime("%Y%m%d%H%M")))workbook = xlsxwriter.Workbook(newfile)sheet = workbook.add_worksheet("Sheet1")row = 0# 表头for idx, header in enumerate(header_row):sheet.write(row, idx, header)row += 1# flavorflavors = get_openstack_flavor_names()  # todo,从数据库获取数据列表cellname = get_excel_cell_name(row, header_row.index("flavor"))sheet.data_validation(cellname, {"validate": "list", "source": flavors})# imageimages = get_openstack_image_names()    #todo,从数据库获取数据列表cellname = get_excel_cell_name(row, header_row.index("image"))sheet.data_validation(cellname, {"validate": "list", "source": images})workbook.close()return newfile@app.route()    # 略
def download():file_path = generate_excel_template()return send_file(file_path, as_attachment=True)

注意:在该方法中,是将列表的内容直接放在了source里,xlsxwriter对此有所限制,内容长度不超过255,否则无法生效,该单元格最终会变成普通的单元格。

列表维护在单独sheet中

对于列表内容较长的场景,建议单独创建一个sheet,用于作为下拉列表的选项。上述代码可改造为:

def save_data_validate_options_sheet(workbook, object_options):"""保存数据校验的待选项到单独的sheet,object_options格式为{'flavor':[], 'image':[]}"""key2cellrange = {}opt_sheet = workbook.add_worksheet("options")col = 0for k in object_options:key2cellrange[k] = ""opt_sheet.write(0, col, k)row = 1for opt in object_options[k]:opt_sheet.write(row, col, opt)row += 1col_char = get_column(col)cellrange = "='{sheet}'!${col}${row1}:${col}${row2}".format(sheet=sheetname,col=col_char, row1=2, row2=row)key2cellrange[k] = cellrangecol += 1return key2cellrangedef generate_excel_template():newfile = os.path.join(current_app.config['TMP_DIR'], 'download', 'Template-%s.xlsx' % (time.strftime("%Y%m%d%H%M")))workbook = xlsxwriter.Workbook(newfile)sheet = workbook.add_worksheet("Sheet1")row = 0# 表头for idx, header in enumerate(header_row):sheet.write(row, idx, header)row += 1# 统一获取待选项flavors = get_openstack_flavor_names()  # todo,从数据库获取数据列表images = get_openstack_image_names()    #todo,从数据库获取数据列表object_options = {"flavor": flavors, "image": images}key2cellrange = save_data_validate_options_sheet(workbook, object_options)# flavorcellname = get_excel_cell_name(row, header_row.index("flavor"))sheet.data_validation(cellname, {"validate": "list", "source": key2cellrange['flavor']})# imagecellname = get_excel_cell_name(row, header_row.index("image"))sheet.data_validation(cellname, {"validate": "list", "source": key2cellrange['image']})workbook.close()return newfile

http://www.ppmy.cn/news/1072647.html

相关文章

C# 课后练习题

17. XAF框架下的导航按钮 using System; using System.Collections.Generic; using System.Line; using System.Text; using System.Threading.Tasks;namespace Tutorial_XAF.Module.BussinessObjects {[XAFDisplayName("测试")][NavigationItem("这是导航&quo…

魏副业而战:开学季,闲鱼卖什么好?

我是魏哥&#xff0c;与其躺平&#xff0c;不如魏副业而战&#xff01; 现在八月底了&#xff0c;意味着暑假结束&#xff0c;新的学期将要开始。 作为闲鱼卖家&#xff0c;可顺势布局一下。 那卖什么好呢&#xff1f; 开学季嘛&#xff0c;卖学习相关的&#xff0c;例如&a…

浅谈安防视频监控平台EasyCVR视频汇聚平台对于夏季可视化智能溺水安全告警平台的重要性

每年夏天都是溺水事故高发的时期&#xff0c;许多未成年人喜欢在有水源的地方嬉戏&#xff0c;这导致了悲剧的发生。常见的溺水事故发生地包括水库、水坑、池塘、河流、溪边和海边等场所。 为了加强溺水风险的提示和预警&#xff0c;完善各类安全防护设施&#xff0c;并及时发现…

MySQL 如何获取行号

MySQL 如何获取行号 一、使用MySQL变量获取行号二、利用MySQL内置函数获取行号2.1、ROW_NUMBER()2.2、RANK()2.3、DENSE_RANK() 三、总结 一、使用MySQL变量获取行号 MySQL变量是一种用于存储和操纵数据的数据类型。通过在SQL查询中使用变量&#xff0c;我们可以创建一个MySQL…

【校招VIP】算法考点之堆排

考点介绍&#xff1a; 排序算法属于数据结构和算法的基础内容&#xff0c;并且也是大厂笔试中的高频考点。 堆排序是使用一棵树存储序列这个课树只保证跟节点是这棵树中的最小值&#xff0c;但并不保证其他节点是按顺序的。因此他的排序是每次从堆中取得堆顶&#xff0c;取得 n…

一张图看懂 USDT三种类型地址 Omni、ERC20、TRC20的区别

USDT是当前实用最广泛&#xff0c;市值最高的稳定币&#xff0c;它是中心化的公司Tether发行的。在今年的4月17日之前&#xff0c;市场上存在着2种不同类型的USDT。4月17日又多了一种波场TRC20协议发行的USDT&#xff0c;它们各自有什么区别呢?哪个转账最快到账&#xff1f;哪…

【12期】谈一谈redis两种持久化机制的区别?

Redis两类持续性的方法 RDB方案可以在规定时间间隔内创建数据集的时间点快照。 AOF方案记录了服务器执行的所有写操作命令&#xff0c;并在服务器启动时通过重新执行这些命令来还原数据集。AOF文件完全遵循Redis协议格式保存&#xff0c;新命令会被追加到文件末尾。此外&#…

数学建模——校园供水系统智能管理

import pandas as pd data1pd.read_excel("C://Users//JJH//Desktop//E//附件_一季度.xlsx") data2pd.read_excel("C://Users//JJH//Desktop//E//附件_二季度.xlsx") data3pd.read_excel("C://Users//JJH//Desktop//E//附件_三季度.xlsx") data4…