Search code examples
pythonpython-docx

Changing Paragraph formatting in python-docx


I am trying to change the formatting for multiple paragraphs using Python's python-docx module.

from docx import Document
from docx.shared import Pt
from docx.shared import Inches
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.section import WD_ORIENTATION
from content import report_content, provinces, report_date, introduction, intro_content

alignment_dict = {'justify': WD_PARAGRAPH_ALIGNMENT.JUSTIFY,
                  'center': WD_PARAGRAPH_ALIGNMENT.CENTER,
                  'centre': WD_PARAGRAPH_ALIGNMENT.CENTER,
                  'right': WD_PARAGRAPH_ALIGNMENT.RIGHT,
                  'left': WD_PARAGRAPH_ALIGNMENT.LEFT}

orientation_dict = {'portrait': WD_ORIENTATION.PORTRAIT,
                    'landscape': WD_ORIENTATION.LANDSCAPE}

document = Document()


def change_orientation(orientation='portrait', set_left_margin=1.0, set_right_margin=1.0):
    section = document.sections[-1]
    new_width, new_height = section.page_height, section.page_width
    section.orientation = orientation_dict[orientation]
    section.page_width = new_width
    section.page_height = new_height
    section.left_margin = Inches(set_left_margin)
    section.right_margin = Inches(set_right_margin)


def add_logo(path, align):
    document.add_picture(path, width=Inches(4.5), height=Inches(1.5))
    last_paragraph = document.paragraphs[-1]
    last_paragraph.alignment = alignment_dict[align]


def add_content(content, space_after, font_name='Arial', font_size=11, line_spacing=0, space_before=0,
                align='justify', keep_together=True, keep_with_next=False, page_break_before=False,
                widow_control=False, set_bold=False, set_italic=False, set_underline=False, set_all_caps=False):
    paragraph = document.add_paragraph(content)
    style = document.styles['Normal']
    font = style.font
    font.name = font_name
    font.size = Pt(font_size)
    font.bold = set_bold
    font.italic = set_italic
    font.all_caps = set_all_caps
    font.underline = set_underline
    paragraph_format = paragraph.paragraph_format
    paragraph_format.alignment = alignment_dict.get(align.lower())
    paragraph_format.space_before = Pt(space_before)
    paragraph_format.space_after = Pt(space_after)
    paragraph_format.line_spacing = line_spacing
    paragraph_format.keep_together = keep_together
    paragraph_format.keep_with_next = keep_with_next
    paragraph_format.page_break_before = page_break_before
    paragraph_format.widow_control = widow_control


def create_numbered_list():
    pass


def add_subheading(subheading, level):
    document.add_heading(subheading, level)


change_orientation(orientation='landscape', set_left_margin=0.5, set_right_margin=0.5)
add_logo('logo.png', 'center')
add_content(report_content, align='Center', space_before=40, space_after=20, line_spacing=1, font_name='Arial',
            set_bold=True, set_all_caps=True)
add_content(provinces, align='Center', space_before=20, space_after=20, line_spacing=1, font_name='Arial',
            set_bold=True, set_all_caps=True)
add_content(report_date, align='Center', space_before=20, space_after=20, line_spacing=1, font_name='Arial',
            set_bold=True, set_all_caps=True)
document.add_page_break()

add_subheading(introduction, level=1)

add_content(intro_content, space_after=20, space_before=20)

document.save('demo.docx')

The problem is every time I add formatting to a new paragraph block via the add_content method the formatting for the older blocks gets changed as the formatting for the current block.

Why am I not being able to retain the formatting, why does it get reset to the formatting of the latest block?


Solution

  • Try this code. use add_style to add new style. document.styles['Normal'] is a system style I test it ok

    from docx.enum.style import WD_STYLE_TYPE
    #.........................
    def add_content(content, space_after, font_name='Arial', font_size=16, line_spacing=0, space_before=0,
                    align='justify', keep_together=True, keep_with_next=False, page_break_before=False,
                    widow_control=False, set_bold=False, set_italic=False, set_underline=False, set_all_caps=False,style_name=""):
        paragraph = document.add_paragraph(content)
        paragraph.style = document.styles.add_style(style_name, WD_STYLE_TYPE.PARAGRAPH)
        font = paragraph.style.font
        font.name = font_name
        font.size = Pt(font_size)
        font.bold = set_bold
        font.italic = set_italic
        font.all_caps = set_all_caps
        font.underline = set_underline
        paragraph_format = paragraph.paragraph_format
        paragraph_format.alignment = alignment_dict.get(align.lower())
        paragraph_format.space_before = Pt(space_before)
        paragraph_format.space_after = Pt(space_after)
        paragraph_format.line_spacing = line_spacing
        paragraph_format.keep_together = keep_together
        paragraph_format.keep_with_next = keep_with_next
        paragraph_format.page_break_before = page_break_before
        paragraph_format.widow_control = widow_control
    
    add_content("1234", align='Center', space_before=40, space_after=20, line_spacing=1, font_name='Arial', font_size=16,
                set_bold=True, set_all_caps=True,style_name ="Normal1")
    add_content("12345", align='Center', space_before=20, space_after=20, line_spacing=1, font_name='Arial',font_size=14,
                set_bold=True, set_all_caps=True,style_name ="Normal2")