Skip to content

Fields

A Word field is a live value the application computes — a page number, a date, the current chapter heading. docx_plus.fields inserts them and sets the flag that makes Word recalculate.

Fields render blank until Word recalculates them

Everything on this page writes an empty placeholder to disk. Call mark_fields_dirty(doc) once, after all your inserts and before save, so Word populates them on open.

The same applies to TOCs and captions and cross-references. Footnotes and bookmarks are not fields and don't need it.

Page numbers

from docx_plus.fields import add_page_number_field, mark_fields_dirty

p = doc.sections[0].footer.paragraphs[0]
p.add_run("Page ")
add_page_number_field(p)                        # PAGE
p.add_run(" of ")
add_page_number_field(p, field="NUMPAGES")      # also: "SECTIONPAGES"

mark_fields_dirty(doc)

add_page_number_field(paragraph, *, field="PAGE", format=None)field is "PAGE", "NUMPAGES", or "SECTIONPAGES". format is a field switch such as r"\* ARABIC".

Dates

from docx_plus.fields import add_date_field

add_date_field(doc.add_paragraph(), format="MMMM d, yyyy", auto_update=True)

add_date_field(paragraph, *, format="MMMM d, yyyy", auto_update=True). With auto_update=False it emits a frozen CREATEDATE instead of a live DATE.

A running header showing the current chapter

STYLEREF re-resolves per page — it is the only cross-reference that needs no bookmark.

from docx_plus.fields import add_style_reference

header = doc.sections[0].header.paragraphs[0]
header.add_run("Chapter: ")
add_style_reference(header, style="Heading 1")

style here is the style name, not the style id

"Heading 1", with the space — not "Heading1". This is the one place in the library that takes a name, because that is what the field instruction grammar accepts. Passing an int uses an outline level (1–9) instead.

add_style_reference(paragraph, *, style, search_from_bottom=False, number=None, position=False, suppress_non_delimiters=False, preserve_formatting=True). search_from_bottom (\l) takes the last match on the page rather than the first.

Any other field

from docx_plus.fields import add_field

add_field(doc.add_paragraph(),
          instruction=r'MERGEFIELD FirstName \* MERGEFORMAT')

add_field(paragraph, *, instruction, initial_text="") — spaces are normalised around instruction. Every helper on this page returns the begin <w:r> element, so you can navigate or relocate the field.

Reading fields back

from docx_plus.fields import read_fields

for f in read_fields(doc):
    print(f.instruction, f.paragraph_index)

Making Word recalculate

from docx_plus.fields import mark_fields_dirty

mark_fields_dirty(doc)
doc.save("report.docx")

This writes <w:updateFields w:val="true"/> into settings.xml. Word reads the flag on open, recalculates every field, and resets it — it is a one-shot mechanism, not persistent state. The call is idempotent, so once before saving is exactly right.

Readers can also force it manually in Word with Ctrl+A, F9.

See also