6.python-docx inserts a table into word

1. Introduction

A table (table) object is composed of multiple row (row) objects, and a row (row) object is composed of multiple cell (cell) objects. Cell objects contain paragraph objects, and with paragraph objects we can add text and set styles.

2. Insert table

Divided into two situations:
a: Fixed rows and columns
b: Unfixed rows and columns

1. Fixed rows and columns

Writing method one:

from docx import Document
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import RGBColor
document = Document()
t1 = document.add_table(rows=4, cols=2, style='Colorful List')
#Add header
t1.rows[0].cells[0].text = "Category"
t1.rows[0].cells[1].text = "code name"

t1.rows[1].cells[0].text = "A"
t1.rows[1].cells[1].text = "001"

t1.rows[2].cells[0].text = "B"
t1.rows[2].cells[1].text = "002"

t1.rows[3].cells[0].text = "C"
t1.rows[3].cells[1].text = "003"

run1 = t1.rows[0].cells[0].paragraphs[0].add_run('category')
t1.rows[0].cells[0].paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
run1.font.color.rgb = RGBColor(0, 255, 0)
run1.bold=True

# Save form
document.save('Form 1.docx')

result

Writing method two: add content in a loop

from docx import Document
import numpy as np
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import RGBColor

arr = np.array([['Category 1', 'Code 1'], ['A', '001'], ['B', '002'], ['C', '003']])
document = Document()
t1 = document.add_table(rows=4, cols=2, style='Colorful List')


# Add in loop
for i, row in enumerate(t1.rows):
    print(i)
    for j, cell in enumerate(row.cells):
        # Get the paragraph object in the cell
        paragraph = cell.paragraphs[0]
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        # The run here can set some properties
        run = paragraph.add_run(arr[i, j])
        if i == 2:
            run.font.color.rgb = RGBColor(0, 255, 0)

# Save form
document.save('Form 2.docx')

result:

1. Unfixed rows and columns

The rows and columns of the table are not determined in advance and need to be added temporarily based on the data situation. You can first create a 1*1 table, then add columns to the right and rows to the bottom.

4. Exercise: Use python-docx to automatically generate tables to simplify the workflow

1.Background

Different jobs sometimes use fixed forms to fill in non-fixed information. For example:

2. Workflow

Old workflow:
Open the two tables, fill in the personal information in the corresponding positions in the table, and save. In this way, when there is a lot of information to be filled in, the work will be cumbersome.

New workflow:

  1. Use python-docx to write a script, run the script – enter personal information – automatically generate two word templates

  2. Functions of the python-docx library used in the script:
    (1) Create and merge tables
    (2), add text
    (3) Set text attributes (such as size, bold, underline, center, etc.)

  3. Installing python-docx has already been said

  4. Create a new document

"""
Create a new document
"""
document = Document()
"""
Zero.Set the font of the text
"""
document.styles['Normal'].font.name = "Times New Roman"
document.styles['Normal'].element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')
  1. Create and merge tables
    Merging cells involves subscripts, so you can use a piece of code to make each cell display its subscript.
document1 = Document('word template 1.docx')
table = document1. tables[0]
for row, obj_row in enumerate(table.rows):
for col, cell in enumerate(obj_row.cells):
cell.text = cell.text + "%d,%d" % (row, col)
document1.save("word template 1.docx with row and column marks")
"""
1. Add a table with 37 rows and 13 columns with a total of 481 cells
"""
table = document.add_table(rows=37, cols=13, style="Table Grid")

"""
2. Merge cells
"""
# first row
table. cell(0, 0). merge(table. cell(2, 2))
table. cell(0, 3). merge(table. cell(2, 6))
table. cell(0, 7). merge(table. cell(2, 9))
table. cell(0, 10). merge(table. cell(2, 12))

# second line
table. cell(3, 0). merge(table. cell(5, 2))
table. cell(3, 3). merge(table. cell(5, 5))
table. cell(3, 6). merge(table. cell(5, 6))
table. cell(3, 7). merge(table. cell(5, 9))
table.cell(3, 10).merge(table.cell(5, 10))
table.cell(3, 11).merge(table.cell(5, 12))

# The third row
table.cell(6, 0).merge(table.cell(8, 2))
table.cell(6, 3).merge(table.cell(8, 12))

# fourth line
table.cell(9, 0).merge(table.cell(12, 2))
table.cell(9, 3).merge(table.cell(12, 6))
table.cell(9, 7).merge(table.cell(10, 9))
table.cell(11, 7).merge(table.cell(12, 9))
table.cell(9, 10).merge(table.cell(10, 12))
table.cell(11, 10).merge(table.cell(12, 12))

# The fifth line
table.cell(13, 0).merge(table.cell(18, 2))
table.cell(13, 3).merge(table.cell(18, 12))

# sixth line
table.cell(19, 0).merge(table.cell(24, 2))
table.cell(19, 3).merge(table.cell(24, 12))

# the seventh line
table.cell(25, 0).merge(table.cell(30, 2))
table.cell(25, 3).merge(table.cell(30, 12))

# eighth line
table.cell(31, 0).merge(table.cell(36, 2))
table.cell(31, 3).merge(table.cell(36, 12))
  1. Receive the content entered by the user, that is, the non-fixed content in the table
"""
Receive input from students
"""
departments = input('Departments:')
specialty = input('specialty:')
name = input('Name:')
gender = input('Gender:')
school_num = input('Student number:')
school_time_year_month1 = input('School start time year and month:')
school_time_year_month2 = input('School deadline year and month:')
home_address = input('Home address:')
home_num = input('Home contact information:')
personal_tel = input('Personal contact information:')
reason = input('My reason for applying:')
  1. Get the merged cells of each row
# 1. Get all the cells of each row after the merged cells
hdr_cells0 = table.rows[0].cells
hdr_cells3 = table.rows[3].cells
hdr_cells6 = table.rows[6].cells
hdr_cells9 = table.rows[9].cells
hdr_cells12 = table.rows[12].cells
hdr_cells15 = table.rows[15].cells
hdr_cells21 = table.rows[21].cells
hdr_cells27 = table.rows[27].cells
hdr_cells32 = table.rows[32].cells
  1. Define two functions to write content to the cell, one is bold and the other is not bold
def add_content_center(cell, con):
    """
    Fill in non-fixed information
    Write content to the cell without making the font bold
    :param cell:
    :param con:
    :return:
    """
    p = cell.add_paragraph('')
    p.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.text = con
    cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER


def add_content_center_bold(cell, con):
    """
    Fill in fixed information
    Write content to the cell and make the font bold
    :param cell:
    :param con:
    :return:
    """
    cell.text = con
    cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.paragraphs[0].runs[0].font.bold = True
  1. Add content to each merged cell of each row in turn
# Contents of the first line
add_content_center_bold(hdr_cells0[0], "College (Department)")
add_content_center(hdr_cells0[3], departments + 'house')
add_content_center_bold(hdr_cells0[7], 'professional class')
add_content_center(hdr_cells0[10], specialty)

# Contents of the second line
add_content_center_bold(hdr_cells3[0], "Name")
add_content_center(hdr_cells3[3], name)
add_content_center_bold(hdr_cells3[6], "Gender")
add_content_center(hdr_cells3[7], gender)
add_content_center_bold(hdr_cells3[10], 'student number')
add_content_center(hdr_cells3[11], school_num)

# The third line of content
add_content_center_bold(hdr_cells6[0], "school time")
add_content_center(hdr_cells6[3], school_time_year_month1 + "-" + school_time_year_month2)
# Fourth line
add_content_center_bold(hdr_cells9[0], "Home mailing address")
add_content_center(hdr_cells9[3], home_address)
add_content_center_bold(hdr_cells9[7], "Family Contact Information")
add_content_center(hdr_cells9[10], home_num)
add_content_center_bold(table.rows[12].cells[7], "personal contact information")
add_content_center(table. rows[12]. cells[10], personal_tel)

# The fifth line
add_content_center_bold(hdr_cells15[0], "The reason for my application")
add_content_center(hdr_cells15[3], reason + "\
\
Student's signature\
\
\t\tyear\tmonth\tday")

# Line 6
# hdr_cells21[0].vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
add_content_center_bold(hdr_cells21[0], "Department leader's opinion")
add_content_center(hdr_cells21[3], "\
\
leadership signature\
\
\t\tyear\tmonth\tday")

# Line 7
add_content_center_bold(hdr_cells27[0], "Student Office Opinions")
add_content_center(hdr_cells27[3], "\
\
leadership signature\
\
\t\tyear\tmonth\tday")

# Line 8
add_content_center_bold(hdr_cells32[0], "Approval by the head of the school")
add_content_center(hdr_cells32[3], "\
\
leadership signature\
\
\t\tyear\tmonth\tday")

3. Complete code

from docx import Document
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn

from docx.shared import RGBColor, Pt

"""
Receive input from students
"""
departments = input('Department:')
specialty = input('Professional:')
name = input('Name:')
gender = input('Gender:')
school_num = input('student number: ')
school_time_year_month1 = input('School start time year and month:')
school_time_year_month2 = input('School deadline year and month:')
home_address = input('Home correspondence address:')
home_num = input('Home contact information:')
personal_tel = input('Personal contact information:')
reason = input('My reason for applying:')
"""
Create a new document
"""
document = Document()
"""
Zero.Set the font of the text
"""
document.styles['Normal'].font.name = "Times New Roman"
document.styles['Normal'].element.rPr.rFonts.set(qn('w:eastAsia'), u'Arial')

"""
1. Add a table with 37 rows and 13 columns with a total of 481 cells
"""
table = document.add_table(rows=37, cols=13, style="Table Grid")

"""
2. Merge cells
"""
# first row
table.cell(0, 0).merge(table.cell(2, 2))
table. cell(0, 3). merge(table. cell(2, 6))
table. cell(0, 7). merge(table. cell(2, 9))
table. cell(0, 10). merge(table. cell(2, 12))

# second line
table. cell(3, 0). merge(table. cell(5, 2))
table. cell(3, 3). merge(table. cell(5, 5))
table. cell(3, 6). merge(table. cell(5, 6))
table. cell(3, 7). merge(table. cell(5, 9))
table.cell(3, 10).merge(table.cell(5, 10))
table.cell(3, 11).merge(table.cell(5, 12))

# The third row
table.cell(6, 0).merge(table.cell(8, 2))
table. cell(6, 3). merge(table. cell(8, 12))

# Fourth line
table.cell(9, 0).merge(table.cell(12, 2))
table.cell(9, 3).merge(table.cell(12, 6))
table.cell(9, 7).merge(table.cell(10, 9))
table.cell(11, 7).merge(table.cell(12, 9))
table.cell(9, 10).merge(table.cell(10, 12))
table.cell(11, 10).merge(table.cell(12, 12))

# The fifth line
table.cell(13, 0).merge(table.cell(18, 2))
table.cell(13, 3).merge(table.cell(18, 12))

# Line 6
table.cell(19, 0).merge(table.cell(24, 2))
table.cell(19, 3).merge(table.cell(24, 12))

# Line 7
table.cell(25, 0).merge(table.cell(30, 2))
table.cell(25, 3).merge(table.cell(30, 12))

# Line 8
table.cell(31, 0).merge(table.cell(36, 2))
table.cell(31, 3).merge(table.cell(36, 12))

"""
3. Add content to the fixed position of the template
1. Get all the cells in each row after the merged cells
2. Add content to each merged cell in each row in turn
"""
# 1. Get all the cells of each row after the merged cells
hdr_cells0 = table.rows[0].cells
hdr_cells3 = table.rows[3].cells
hdr_cells6 = table.rows[6].cells
hdr_cells9 = table.rows[9].cells
hdr_cells12 = table.rows[12].cells
hdr_cells15 = table.rows[15].cells
hdr_cells21 = table.rows[21].cells
hdr_cells27 = table.rows[27].cells
hdr_cells32 = table.rows[32].cells


# 2
def add_content_center(cell, con):
    """
    Fill in non-fixed information
    Write content to the cell, the font is not bold
    :param cell:
    :param con:
    :return:
    """
    p = cell.add_paragraph('')
    p.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.text = con
    cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER


def add_content_center_bold(cell, con):
    """
    Fill in fixed information
    Write content to the cell, the font is bold
    :param cell:
    :param con:
    :return:
    """
    cell.text = con
    cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
    cell.vertical_alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    cell.paragraphs[0].runs[0].font.bold = True


# Contents of the first line
add_content_center_bold(hdr_cells0[0], "College (Department)")
add_content_center(hdr_cells0[3], departments + 'hoard')
add_content_center_bold(hdr_cells0[7], 'Professional class')
add_content_center(hdr_cells0[10], specialty)

# Contents of the second line
add_content_center_bold(hdr_cells3[0], "Name")
add_content_center(hdr_cells3[3], name)
add_content_center_bold(hdr_cells3[6], "gender")
add_content_center(hdr_cells3[7], gender)
add_content_center_bold(hdr_cells3[10], 'student number')
add_content_center(hdr_cells3[11], school_num)

# The third line of content
add_content_center_bold(hdr_cells6[0], "school time")
add_content_center(hdr_cells6[3], school_time_year_month1 + "-" + school_time_year_month2)
# Fourth line
add_content_center_bold(hdr_cells9[0], "Home correspondence address")
add_content_center(hdr_cells9[3], home_address)
add_content_center_bold(hdr_cells9[7], "Family Contact Information")
add_content_center(hdr_cells9[10], home_num)
add_content_center_bold(table.rows[12].cells[7], "Personal contact information")
add_content_center(table.rows[12].cells[10], personal_tel)

# The fifth line
add_content_center_bold(hdr_cells15[0], "Reason for my application")
add_content_center(hdr_cells15[3], reason + "\
\
Signature of student\
\
\t\tYear\tMonth\tDay")

# Line 6
# hdr_cells21[0].vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
add_content_center_bold(hdr_cells21[0], "Opinions of department leaders")
add_content_center(hdr_cells21[3], "\
\
Leader's signature\
\
\t\tYear\tMonth\tDay")

# Line 7
add_content_center_bold(hdr_cells27[0], "Opinions of the Student Affairs Office")
add_content_center(hdr_cells27[3], "\
\
Leader's signature\
\
\t\tYear\tMonth\tDay")

# Line 8
add_content_center_bold(hdr_cells32[0], "Approval by the school leader")
add_content_center(hdr_cells32[3], "\
\
Leader's signature\
\
\t\tYear\tMonth\tDay")

# document1 = Document('word template 1.docx')
# table = document1. tables[0]
# for row, obj_row in enumerate(table.rows):
# for col, cell in enumerate(obj_row.cells):
# cell.text = cell.text + "%d,%d" % (row, col)
# document1.save("Word template 1.docx with row and column marks")
document.save("word template 1.docx")

Note: First create a table with 37 rows and 13 columns and write it into word, then use document1 = Document(‘word template 1.docx’) to open the document, and write the corresponding subscript in each cell, so that we can merge the units grid
result:

5. Add background color to the cell

The official pythondocx library still does not support this option. However, you can try to implement it yourself. The property you are looking for is called cell shading and is located under cell properties
Solution: Add the shading element (w:shd) to the cell property (w:tcPr)
Wrote a simple function that does the following:

def _set_cell_background(cell, fill, color=None, val=None):
    """
    @fill: Specifies the color to be used for the background
    @color: Specifies the color to be used for any foreground
    pattern specified with the val attribute
    @val: Specifies the pattern to be used to lay the pattern
    color over the background color.
    """
    from docx.oxml.shared import qn # feel free to move these out
    from docx.oxml.xmlchemy import OxmlElement

    cell_properties = cell._element.tcPr
    try:
        cell_shading = cell_properties.xpath('w:shd')[0] # in case there's already shading
    except IndexError:
        cell_shading = OxmlElement('w:shd') # add new w:shd element to it
    if fill:
        cell_shading.set(qn('w:fill'), fill) # set fill property, respecting namespace
    if color:
        pass # TODO
    if val:
        pass # TODO
    cell_properties.append(cell_shading) # finally extend cell props with shading element

Feel free to extend other properties if needed
So based on your example, once you have the table, before saving the document, add the following lines:

_set_cell_background(table.rows[0].cells[0], 'FF0000')
doc. save("Testing. docx")