Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

openpyxl in Python delete_rows function breaks the merged cell

I use openpyxl 2.6.0 in Python3 (with Django).

I want to manipulate my excel skelton sheet (some cells are merged) to delete a row. But after deleting the row, the merged cells are no longer merged.

I want to keep the merged cells even if some rows are deleted.

Code and excel sample is below.

def excelsample(request):

    wb = openpyxl.load_workbook(os.path.join(settings.BASE_DIR, 'static', 'excel', 'sample.xlsx'))

    sheet = wb['Sheet1']
    sheet.delete_rows(6) # delete 6th row

    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = 'attachment; filename="{fn}"'.format(fn=urllib.parse.quote("excelsample.xlsx"))

    wb.save(response)

    return response

Before:

enter image description here

After:

enter image description here

like image 655
Otsuki Takaya Avatar asked Mar 06 '26 07:03

Otsuki Takaya


2 Answers

There is an issue on the openpyxl bug tracker covering this. It has been marked as invalid.

The basic problem is that for this to work, all merged cell ranges would need to be checked and updated after the row delete. There are several complex/difficult issues of similar nature that have been deemed to be of minimal value and thus have not been implemented.

You could do this yourself if needed. There is an attribute (merged_cells) on the worksheet that you could update after the row delete.

Code:

def delete_row_with_merged_ranges(sheet, idx):
    sheet.delete_rows(idx)
    for mcr in sheet.merged_cells:
        if idx < mcr.min_row:
            mcr.shift(row_shift=-1)
        elif idx <= mcr.max_row:
            mcr.shrink(bottom=1)

Test Code:

wb = openpyxl.load_workbook('csvfile.xlsx')

sheet = wb['Sheet2']
delete_row_with_merged_ranges(sheet, 6)

wb.save('csvfile2.xlsx')
like image 90
Stephen Rauch Avatar answered Mar 07 '26 19:03

Stephen Rauch


For openpyxl 3.04 and Python 3.8.5 the code in Stephen Rauch's answer works only if we change < to <= in the elif clause:

def delete_row_with_merged_ranges(sheet, idx):
    sheet.delete_rows(idx)
    for mcr in sheet.merged_cells:
        if idx < mcr.min_row:
            mcr.shift(row_shift=-1)
        elif idx < mcr.max_row:
            mcr.shrink(bottom=1)
like image 43
Alexey Grom Avatar answered Mar 07 '26 19:03

Alexey Grom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!