简体   繁体   中英

Is there a way to make merged cells filterable in excel using Openpyxl?

I was looking for a way to make merged cells filterable using openpyxl.

Eg Filtering on first name "John" in the below workbook:

工作簿

Should return the first three rows: 所需的过滤器行为 Rather than returning only the top row (the default excel behavior): 默认 Excel 行为

The problem is that by default merged ranges only contain a value in the top left cell of the range: Default merged cell values

Using openpyxl is it possible to overwrite the None values within merged cells effectively making them filterable? Desired Merged cell values

For reference, you can already create filterable merged cells using macros or manual formatting as per the answer here: https://stackoverflow.com/a/49817670/14251756

I've already tried overwriting the none values using the below script but get the error AttributeError: 'MergedCell' object attribute 'value' is read-only

import openpyxl
wb = openpyxl.load_workbook("Workbook")
ws = wb['Worksheet']

#Get list of ranges of merged cells
merged_cell_ranges = ws.merged_cells.ranges
merged_cell_ranges = list(map(str,merged_cell_ranges))

#Iterate through ranges and write top merged cell value to empty cells
for merged_range in merged_cell_ranges:
    for row in ws[merged_range]:
        for cell in row:
            cell.value = ws[merged_range.split(':')[0]].value

Far from ideal, but I achieved the desired result by modifying the openpyxl source.

The function to modify is located here: https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/3.0/openpyxl/worksheet/worksheet.py#L586

you can simply add an argument to choose whether or not the cells become merged cells and therefor "cleaned".

The modified function now looks like this:

    def merge_cells(self, range_string=None, start_row=None, start_column=None, end_row=None, end_column=None, clean=True):
        """ Set merge on a cell range.  Range is a cell range (e.g. A1:E1) """
        if range_string is None:
            cr = CellRange(range_string=range_string, min_col=start_column, min_row=start_row,
                      max_col=end_column, max_row=end_row)
            range_string = cr.coord
        mcr = MergedCellRange(self, range_string)
        self.merged_cells.add(mcr)
        if clean:
            self._clean_merge_range(mcr)
        else:
            mcr.format()

Simply add clean=False to keep the values.

ws.merge_cells('A2:A9', clean=False)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM