openpyxl导致Excel中现有的数据验证丢失

5
我正在使用openpyxl导入现有的Excel表格,并尝试填写一些值并重新保存,但我注意到在这样做时,电子表格中现有的数据验证下拉框会出现问题。即使只加载电子表格,不进行任何其他操作,然后重新保存,这种情况也会发生,因此似乎与openpyxl本身有关。电子表格中的数据验证包括某些单元格中的下拉框,这些下拉框的可能值来自大约20列之外的一组其他单元格(这是为了为公司生成QC报告)。例如,单元格C13具有初始数据验证“源”为$Z$6:$AB$6,但在加载和保存Excel表格后,该单元格被错误地更改为$Z$5:$AB$5。奇怪的是,这并不是所有单元格都一致的;一些单元格仍保持正确的范围,而一些单元格则偏移了五行左右。看起来只是行数有误,而不是列数。所有带有数据验证的单元格都已合并,我不确定这是否重要。有人知道为什么会发生这种情况,或者如何解决吗?代码不多,但这里是一个简单的加载/保存函数示例,可以导致此问题:
    wb = load_workbook(filename='myspreadsheet.xlsx')
    wb.save('myspreadsheet.xlsx')

预先感谢! 罗伯特


我尝试过了,但无法重现这个问题。你正在使用最新版本的 openpyxl 吗(目前为 2.4.7)? - Xukrao
嗨Xukrao,是的,我正在使用最新版本的openpyxl。我注意到在尝试重新创建问题时,有时在具有示例数据验证的简单电子表格中不会发生。我重新创建了一个示例电子表格,在其中出现了此问题,但似乎无法在此处上传它,因此这是一个带有电子表格的dropbox链接:https://www.dropbox.com/s/sbw07makodkg7oo/DataValidationErrorExample.XLSX?dl=0 您可以看到Test1-3的“DV”行与其“row”选项对齐,但在通过openpyxl传递此电子表格后,您将看到链接已损坏。 - Robert Harris
如果Dropbox链接无法使用,我可以通过电子邮件发送示例,请提供电子邮件地址。谢谢。 - Robert Harris
经过6年,我面临着同样的问题,没有任何解决办法,因为openpyxl只是移除了数据验证,因为它不受支持。 用户警告:不支持数据验证扩展,并将被移除。 - Priyanshu
2个回答

2
可能是您的Excel表格为重叠单元格范围定义了数据验证,导致openpxyl和/或Excel混淆。
使用以下代码时:
wb = load_workbook(filename='DataValidationErrorExample.XLSX')
ws = wb.worksheets[0]
print(ws.data_validations)

I get:

<openpyxl.worksheet.datavalidation.DataValidationList object>
Parameters:
disablePrompts=None, xWindow=None, yWindow=None, count=10, dataValidation=[<openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C15:C28 D15:D28 E15:E28 F15:F28 G15:G28 H15:H28 I15 J15 K15', formula1='$Z$12:$AB$12', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='I12 J12 K12', formula1='$Z$5:$AC$5', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C13:C26 D13:D26 E13:E26 F13:F26 G13:G26 H13:H26 I13 J13 K13', formula1='$Z$6:$AB$6', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C12:C25 D12:D25 E12:E25 F12:F25 G12:G25 H12:H25', formula1='$Z$5:$AB$5', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='G8', formula1='$Z$8:$AB$8', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C16:C29 D16:D29 E16:E29 F16:F29 G16:G29 H16:H29 I16 J16 K16', formula1='$Z$9:$AA$9', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C17:C30 D17:D30 E17:E30 F17:F30 G17:G30 H17:H30 I17 J17 K17', formula1='$Z$10:$AC$10', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='C14:C27 D14:D27 E14:E27 F14:F27 G14:G27 H14:H27 I14 J14 K14', formula1='$Z$11:$AA$11', formula2=None, <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='date', errorStyle=None, imeMode=None, operator=None, sqref='C8 D8', formula1='41275', formula2='43101', <openpyxl.worksheet.datavalidation.DataValidation object>
Parameters:
showErrorMessage=True, showDropDown=None, showInputMessage=True, allowBlank=False, errorTitle=None, error=None, promptTitle=None, prompt=None, type='list', errorStyle=None, imeMode=None, operator=None, sqref='J8 K8', formula1='$Z$4:$AA$4', formula2=None]
< p > sqref 属性显示数据验证适用于哪些单元格,您可以看到不同的数据验证之间存在一些重叠。


啊,.data_validations的这个函数很有帮助。但是从输出结果来看,似乎openpyxl一加载数据验证就已经出问题了。如果你在Excel中查看原始电子表格,你会发现链接错误地将C15与C28连接起来(给它们之间的每个单元格都提供了数据验证),而实际上应该只是C15和C28。如果我能找出为什么它会读取那些单元格并在它们之间加上“:”,那可能就是我的问题所在。但我不确定为什么会这样做或如何解决它。再次感谢您的关注。 - Robert Harris
利用从.data_validations得到的知识(openpyxl错误地组合了数据验证单元格范围,例如C12:C25而不是C12、C25),我能够想出一个解决此问题的解决方法。这个问题出现在两个不同行中的单元格共享相同的数据验证输入时。由于对每个事物都有两组行,我复制了我的数据验证输入,使其出现两次,并将每行连接到唯一的数据验证范围。这不是一个完整的解决方案,也不是理想的解决方案,但可以暂时解决问题。如果有人知道完整的解决方案,那仍然会有帮助。 - Robert Harris

1
try this one 
    wb  = load_workbook(excel_file_path,read_only=False)
    sheet = wb[ws]
    for validation in sheet.data_validations.dataValidation:
    # here exist validation we extract from sheet.data_validation
       if validation.formula1  == exist_validation:
            validation.sqref = [C12:C25]
    wb.save()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接