Программное формирование таблиц в Word: библиотека python-docx

Раздел: Офисные форматы -> Работа с документами Word

Библиотека python-docx предоставляет широкие возможности для программного создания и редактирования документов в формате Microsoft Word (.docx). Одной из часто используемых функций является работа с таблицами. В данной статье рассматриваются различные способы формирования таблиц, начиная от простого добавления пустой таблицы и заканчивая настройкой границ, стилей и вложенных структур.

Основные способы создания таблиц

Самый прямой метод - использование метода add_table() объекта Document. Пример создания таблицы 3x3 с последующим заполнением ячеек:

from docx import Document

doc = Document()
table = doc.add_table(rows=3, cols=3)
for row_idx, row in enumerate(table.rows):
    for col_idx, cell in enumerate(row.cells):
        cell.text = f"R{row_idx}C{col_idx}"
doc.save('simple_table.docx')

Python docx таблицы (создание таблиц в документах word с помощью python-docx)

После сохранения открывается документ с таблицей, содержащей три строки и три столбца. В каждой ячейке записан её индекс. Этот приём подходит для быстрого прототипирования, когда требуется просто разместить данные в сетке.

Типичная ошибка: забыть импортировать Document. При попытке создать экземпляр без импорта возникает NameError. Решение - в начале файла добавить from docx import Document.

Другая распространённая проблема - попытка задать таблице нестандартное количество столбцов после добавления. Метод add_table принимает только rows и cols – количество строк и столбцов фиксируется при создании. Для изменения числа столбцов потребуется создать новую таблицу.

Как применить готовый стиль оформления таблицы?

Библиотека поддерживает встроенные стили Word. Для их применения служит свойство style объекта таблицы. Доступные имена можно получить через table.styles или константы из python-docx (например, 'Table Grid', 'Light Grid Accent 1'). Пример:

table = doc.add_table(3, 2)
table.style = 'Light Grid Accent 1'

Такой подход удобен, когда нужна готовая цветовая схема без ручной настройки границ и заливок. Стиль применяется ко всей таблице сразу.

Проблема: не все стили корректно отображаются в разных версиях Word. Рекомендуется проверять конечный документ в целевой среде.

Как добавить строки или столбцы после создания таблицы?

Для добавления строк используется метод add_row(). Добавить столбец напрямую нельзя, но можно создать таблицу с нужным количеством столбцов заранее. Пример динамического роста таблицы:

table = doc.add_table(1, 3)
# Заполняем начальную строку
for i in range(3):
    table.rows[0].cells[i].text = f"Header {i}"
# Добавляем ещё 2 строки
for _ in range(2):
    row = table.add_row()
    for j, cell in enumerate(row.cells):
        cell.text = f"New {j}"

Этот вариант полезен при построчном формировании отчётов, когда количество строк заранее неизвестно.

Распространённая ошибка: попытка обратиться к несуществующей строке после добавления – индексация начинается с 0, и добавленная строка становится последней (table.rows[-1]).

Как объединить несколько ячеек?

Объединение выполняется вызовом метода merge() у ячейки, передавая ей другую ячейку в качестве аргумента. Например, объединение двух верхних ячеек первой строки:

table = doc.add_table(2, 2)
cell_a = table.cell(0, 0)
cell_b = table.cell(0, 1)
merged = cell_a.merge(cell_b)
merged.text = "Объединённая ячейка"

Объединение применимо для шапок таблиц или создания областей под суммарные данные.

Важно: объединять можно только смежные ячейки в пределах строки или столбца. Попытка объединить несмежные ячейки приведет к ошибке ValueError.

Как задать ширину столбцов и высоту строк?

Ширина столбца задаётся через свойство width объекта ячейки или через массив columns. Высота строки – свойство height у строки (объект Row). Пример:

from docx.shared import Inches, Cm

table = doc.add_table(2, 3)
# Установка ширины первого столбца 2 дюйма
table.columns[0].width = Inches(2)
# Установка высоты первой строки 1 см
table.rows[0].height = Cm(1)

Контроль размеров необходим для точного позиционирования контента в профессиональных отчётах.

Проблема: в некоторых версиях Word указанная ширина может игнорироваться, если включена опция автоматической подгонки. Рекомендуется принудительно выставить table.autofit = False.

Как отформатировать текст внутри ячейки (жирный, цвет, выравнивание)?

Текст ячейки хранится в параграфах. Для форматирования получаем первый параграф ячейки (cell.paragraphs[0]) или создаём новый абзац. Затем работаем с объектами run:

from docx.shared import Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH

cell = table.cell(0, 0)
paragraph = cell.paragraphs[0]
run = paragraph.add_run("Пример текста")
run.bold = True
run.font.size = Pt(12)
run.font.color.rgb = RGBColor(255, 0, 0)
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER

Этот метод даёт полный контроль над визуальным стилем содержимого ячеек.

Сложность: в ячейке по умолчанию уже есть пустой параграф. Если добавить новый add_run без очистки, появится пустая строка. Лучше сначала получить cell.paragraphs[0].clear() или обращаться к существующему run.

Как добавить таблицу внутрь другой таблицы (вложенная таблица)?

Любая ячейка может содержать собственную таблицу. Для этого у объекта Cell вызывается add_table():

outer = doc.add_table(2, 2)
inner = outer.cell(0, 0).add_table(2, 2)
inner.cell(0, 0).text = "Внутренняя"

Вложенные таблицы используются для сложной вёрстки, например, в шаблонах документов.

Ограничение: глубокая вложенность может снижать производительность при рендеринге в Word.

Как заполнить таблицу данными из pandas DataFrame?

Итерация по строкам DataFrame и запись значений в ячейки – один из частых сценариев. Пример:

import pandas as pd

df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [30, 25]})
table = doc.add_table(df.shape[0] + 1, df.shape[1])
# Заголовки
for j, col in enumerate(df.columns):
    table.rows[0].cells[j].text = col
# Данные
for i, row in df.iterrows():
    for j, val in enumerate(row):
        table.rows[i + 1].cells[j].text = str(val)

Такой код удобен для автоматической генерации отчётов из аналитических данных.

Ошибка: если в DataFrame есть пропущенные значения (NaN), они преобразуются в строку 'nan'. Желательно предварительно обрабатывать df.fillna('').

Как настроить границы ячеек, чтобы они не были видны?

python-docx не имеет прямого API для управления границами, но можно манипулировать XML-структурой. Пример отключения всех границ таблицы:

from docx.oxml.ns import qn

# Получаем элемент прозрачности границ для всей таблицы
tbl = table._tbl
tblPr = tbl.tblPr if tbl.tblPr is not None else OxmlElement('w:tblPr')
tblBorders = OxmlElement('w:tblBorders')
for border_name in ['top', 'left', 'bottom', 'right', 'insideH', 'insideV']:
    border = OxmlElement(f'w:{border_name}')
    border.set(qn('w:val'), 'none')
    border.set(qn('w:sz'), '0')
    border.set(qn('w:space'), '0')
    border.set(qn('w:color'), 'auto')
    tblBorders.append(border)
tblPr.append(tblBorders)

Этот приём полезен при создании невидимых сеток для выравнивания элементов.

Внимание: ручное редактирование XML может привести к повреждению документа, если не учесть все обязательные атрибуты. Рекомендуется тестировать на копии.

Расширенные примеры работы с таблицами

Пример 1. Создание таблицы с цветной шапкой, объединёнными ячейками и границами

В данном примере формируется таблица 4x3, первая строка используется как заголовок с заливкой и объединением двух последних столбцов. Для заливки используется OxmlElement с установкой цвета.

Пример
from docx import Document
from docx.shared import Inches, RGBColor
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml, OxmlElement

doc = Document()
table = doc.add_table(4, 3, style='Table Grid')

# Объединение ячеек в первой строке: объединяем 1 и 2 столбец (0 и 1)
cell0 = table.cell(0, 0)
cell1 = table.cell(0, 1)
merged = cell0.merge(cell1)
merged.text = "Объединённый заголовок"

# Заливка первой строки (все ячейки в строке имеют один фон)
for cell in table.rows[0].cells:
    shading_elm = parse_xml(f'')
    cell._tc.get_or_add_tcPr().append(shading_elm)

# Заполнение остальных ячеек
for i in range(1, 4):
    for j in range(3):
        table.cell(i, j).text = f"{i},{j}"

# Установка ширины столбцов
table.columns[0].width = Inches(1.5)
table.columns[1].width = Inches(2)
table.columns[2].width = Inches(2)

doc.save('advanced_table.docx')
Результат: документ с таблицей, у которой первая строка (заголовок) имеет синий фон и объединённые первые две ячейки, остальные строки содержат координаты. Ширина столбцов установлена в дюймах.

Пример 2. Таблица с данными из CSV, форматированием чисел и выравниванием

Предположим, имеется CSV-файл с числовыми данными. Загружаем его в pandas, создаём таблицу, форматируем числа с двумя знаками после запятой и выравниваем столбцы по центру.

Пример
import pandas as pd
from docx import Document
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH

df = pd.read_csv('data.csv')  # предположим, столбцы: Name, Value, Score
doc = Document()
rows = len(df) + 1
cols = len(df.columns)
table = doc.add_table(rows, cols, style='Light Grid Accent 1')

# Заголовки
for j, col in enumerate(df.columns):
    cell = table.cell(0, j)
    cell.text = col
    run = cell.paragraphs[0].runs[0]
    run.bold = True
    run.font.size = Pt(11)
    cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER

# Данные
for i, row in df.iterrows():
    for j, val in enumerate(row):
        cell = table.cell(i + 1, j)
        if isinstance(val, (int, float)):
            cell.text = f"{val:.2f}"
        else:
            cell.text = str(val)
        cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER

doc.save('formatted_from_csv.docx')
Результат: таблица с отформатированными заголовками (жирный, по центру) и выровненными по центру числовыми значениями с двумя десятичными знаками.

Пример 3. Настройка индивидуальных границ ячеек (пунктирные линии, толщина)

Этот пример демонстрирует, как задать разные стили границ для разных сторон таблицы через XML. Создаётся таблица 2x2, верхняя граница делается толстой красной, левая – пунктирной синей, остальные – обычными.

Пример
from docx import Document
from docx.oxml.ns import qn, nsdecls
from docx.oxml import OxmlElement

doc = Document()
table = doc.add_table(2, 2)

# Создаём элемент границ в свойствах таблицы
tbl_pr = table._tbl.tblPr
if tbl_pr is None:
    tbl_pr = OxmlElement('w:tblPr')
    table._tbl.insert(0, tbl_pr)

borders = OxmlElement('w:tblBorders')

# Верхняя граница (толстая, красная)
top = OxmlElement('w:top')
top.set(qn('w:val'), 'single')
top.set(qn('w:sz'), '24')  # 24 восьмых точки = 3pt
top.set(qn('w:color'), 'FF0000')
borders.append(top)

# Левая граница (пунктир, синий)
left = OxmlElement('w:left')
left.set(qn('w:val'), 'dashed')
left.set(qn('w:sz'), '8')
left.set(qn('w:color'), '0000FF')
borders.append(left)

# Остальные границы – по умолчанию (сплошная, 0.5pt, чёрная)
for name in ['bottom', 'right', 'insideH', 'insideV']:
    el = OxmlElement(f'w:{name}')
    el.set(qn('w:val'), 'single')
    el.set(qn('w:sz'), '4')
    el.set(qn('w:color'), '000000')
    borders.append(el)

tbl_pr.append(borders)

table.cell(0,0).text = "A"
table.cell(0,1).text = "B"
table.cell(1,0).text = "C"
table.cell(1,1).text = "D"

doc.save('custom_borders.docx')
Результат: таблица с нестандартными границами – верхняя толстая красная, левая пунктирная синяя, остальные стандартные.

Создание таблиц в документах Word с помощью python-docx - comments

En
Python docx таблицы (python)