Possible to insert row at specific position with python-docx?

12.2k Views Asked by At

I'd like to insert a couple of rows in the middle of the table using python-docx. Is there any way to do it? I've tried to use a similar to inserting pictures approach but it didn't work.

If not, I'd appreciate any hint on which module is a better fit for this task. Thanks.

Here is my attempt to mimic the idea for inserting a picture. It's WRONG. 'Run' object has no attribute 'add_row'.

from docx import Document
doc = Document('your docx file')
tables = doc.tables
p = tables[1].rows[4].cells[0].add_paragraph()
r = p.add_run()
r.add_row()
doc.save('test.docx')
6

There are 6 best solutions below

1
On BEST ANSWER

The short answer is No. There's no Table.insert_row() method in the API.

A possible approach is to write a so-called "workaround function" that manipulates the underlying XML directly. You can get to any given XML element (e.g. <w:tbl> in this case or perhaps <w:tr>) from it's python-docx proxy object. For example:

tbl = table._tbl

Which gives you a starting point in the XML hierarchy. From there you can create a new element from scratch or by copying and use lxml._Element API calls to place it in the right position in the XML.

It's a little bit of an advanced approach, but probably the simplest option. There are no other Python packages out there that provide a more extensive API as far as I know. The alternative would be to do something in Windows with their COM API or whatever from VBA, possibly IronPython. That would only work at small scale (desktop, not server) running Windows OS.

A search on python-docx workaround function and python-pptx workaround function will find you some examples.

0
On

I created a video here to demonstrate how to do this because it threw me for a loop the first time. https://www.youtube.com/watch?v=nhReq_0qqVM

    document=Document("MyDocument.docx")
    Table = document.table[0]
    Table.add_row()
    
    for cells in Table.rows[-1].cells:
         cells.text = "test text"
    
    insertion_row = Table.rows[4]._tr
    insertion_row.add_next(Table.rows[-1]._tr)
    
    document.save("MyDocument.docx")

The python-docx module doesn't have a method for this, So the best workaround Ive found is to create a new row at the bottom of the table and then use methods from the xml elements to place it in the position it is suppose to be.

This will create a new row with every cell in the row having the value "test text" and we then add that row underneath of our insertion_row.

0
On

Though there isn't a directly usable api to achieve this according to the python-docx documentation, there is a simple solution without using any other libs such as lxml, just use the underlying data structure provided by python-docx, which are CT_Tbl, CT_Row, etc. These classes do have common methods like addnext, addprevious which can conveniently add element as siblings right after/before current element. So the problem can be solved as below, (tested on python-docx v0.8.10)


    from docx import Document
    doc = Document('your docx file')
    tables = doc.tables
    row = tables[1].rows[4]
    tr = row._tr # this is a CT_Row element
    for new_tr in build_rows(): # build_rows should return list/iterator of CT_Row instance
        tr.addnext(new_tr)
    doc.save('test.docx')

this should solve the problem

0
On

You can add a row in last position by this way :

from win32com import client
doc = word.Documents.Open(r'yourFile.docx'))
doc = word.ActiveDocument
table = doc.Tables(1)  #number of the tab you want to manipulate
table.Rows.Add()
0
On

addnext() in lxml.etree seems like will be the better option to use and its working fine, and the only thing is, i cannot set the height of the row, so please provide some answers, if you know!

current_row = table.rows[row_index] 
table.rows[row_index].height_rule = WD_ROW_HEIGHT_RULE.AUTO
tbl = table._tbl
border_copied = copy.deepcopy(current_row._tr)
tr = border_copied
current_row._tr.addnext(tr)
0
On

You can insert row to the end of the table and then move it in another position as follows:

from docx import Document
doc = Document('your docx file')
t = doc.tables[0]
row0 = t.rows[0] # for example
row1 = t.rows[-1]
row0._tr.addnext(row1._tr)