Question

I am attempting to create a docx file via python-docx and django.

Running the example script (example-makedocument.py) directly with python works. a.k.a "Working Copy". It generates the example docx file as expected.

What I then did was attempt to move that example-makedocument.py code into a Django view. The code at the bottom of this post is the code for that view. You will see i made some minor modifications up front but generally its unchanged.

When running this view i get an error about being unable to find an image file.

[Errno 2] No such file or directory: 'image1.png'

I have:

  • Made sure the folder/file structure is the same as the working copy (it needs its subfolders to work properly)
  • I have tried hard coding the docx.py template_dir to the location which holds the folders/files (i have checked that these result in pointing to the same final path as the working copy)
  • I have removed the image from the example, but it results in the error local variable 'contenttypes' referenced before assignment

I think it has something to do with the path(s) but i am not sure why/how? Can anyone help?

Full python-docx code available here.

My view:

from myapp.libs.docx.docx import *
# ** commented out below line, replaced with above **
#from docx import *

def export_docx(request):

# ** commented out below line **
#if __name__ == '__main__':
    # Default set of relationshipships - the minimum components of a document
    relationships = relationshiplist()

    # Make a new document tree - this is the main part of a Word document
    document = newdocument()

    # This xpath location is where most interesting content lives
    body = document.xpath('/w:document/w:body', namespaces=nsprefixes)[0]

    # Append two headings and a paragraph
    body.append(heading("Welcome to Python's docx module", 1))
    body.append(heading('Make and edit docx in 200 lines of pure Python', 2))
    body.append(paragraph('The module was created when I was looking for a '
        'Python support for MS Word .doc files on PyPI and Stackoverflow. '
        'Unfortunately, the only solutions I could find used:'))

    # Add a numbered list
    points = [ 'COM automation'
             , '.net or Java'
             , 'Automating OpenOffice or MS Office'
             ]
    for point in points:
        body.append(paragraph(point, style='ListNumber'))
    body.append(paragraph('For those of us who prefer something simpler, I '
                          'made docx.'))
    body.append(heading('Making documents', 2))
    body.append(paragraph('The docx module has the following features:'))

    # Add some bullets
    points = ['Paragraphs', 'Bullets', 'Numbered lists',
              'Multiple levels of headings', 'Tables', 'Document Properties']
    for point in points:
        body.append(paragraph(point, style='ListBullet'))

    body.append(paragraph('Tables are just lists of lists, like this:'))
    # Append a table
    tbl_rows = [ ['A1', 'A2', 'A3']
               , ['B1', 'B2', 'B3']
               , ['C1', 'C2', 'C3']
               ]
    body.append(table(tbl_rows))

    body.append(heading('Editing documents', 2))
    body.append(paragraph('Thanks to the awesomeness of the lxml module, '
                          'we can:'))
    points = [ 'Search and replace'
             , 'Extract plain text of document'
             , 'Add and delete items anywhere within the document'
             ]
    for point in points:
        body.append(paragraph(point, style='ListBullet'))

    # Add an image
    relationships, picpara = picture(relationships, 'image1.png',
                                     'This is a test description')
    body.append(picpara)

    # Search and replace
    print 'Searching for something in a paragraph ...',
    if search(body, 'the awesomeness'):
        print 'found it!'
    else:
        print 'nope.'

    print 'Searching for something in a heading ...',
    if search(body, '200 lines'):
        print 'found it!'
    else:
        print 'nope.'

    print 'Replacing ...',
    body = replace(body, 'the awesomeness', 'the goshdarned awesomeness')
    print 'done.'

    # Add a pagebreak
    body.append(pagebreak(type='page', orient='portrait'))

    body.append(heading('Ideas? Questions? Want to contribute?', 2))
    body.append(paragraph('Email <python.docx@librelist.com>'))

    # Create our properties, contenttypes, and other support files
    title    = 'Python docx demo'
    subject  = 'A practical example of making docx from Python'
    creator  = 'Mike MacCana'
    keywords = ['python', 'Office Open XML', 'Word']

    coreprops = coreproperties(title=title, subject=subject, creator=creator,
                               keywords=keywords)
    appprops = appproperties()
    contenttypes = contenttypes()
    websettings = websettings()
    wordrelationships = wordrelationships(relationships)

    # Save our document
    savedocx(document, coreprops, appprops, contenttypes, websettings,
             wordrelationships, 'Welcome to the Python docx module.docx')

========

Updated. Details of the solution i found provided below.

The docx.py code was assuming the path was different than it was. This caused the image1.png file to be "missing". Completing the steps below solved it for me.

  1. Edited the docx.py file and added a variable:

    docx_dir = '/path/to/docx/folder'

  2. Edited the below lines (docx.py) to use the above variable (approx line numbers shown, will differ slightly from original source)

    1. shutil.copyfile(join(docx_dir, picname), join(media_dir, picname))
    2. pixelwidth, pixelheight = Image.open(join(docx_dir, picname)).size[0:2]
  3. The above got rid of the path issues. But now i was faced with the error local variable 'contenttypes' referenced before assignment. I found the error was solved not by anything to do with paths but duplicate names (i don't fully understand why this is still).

Note: below code is located in my view or..if comparing to original source its in the example-makedocument.py

Before:

contenttypes = contenttypes()
websettings = websettings()
wordrelationships = wordrelationships(relationships)

After:

contentt = contenttypes()
webs = websettings()
wordr = wordrelationships(relationships)

# Save our document
savedocx(document, coreprops, appprops, contentt, webs,
         wordr, 'Welcome to the Python docx module.docx')
Was it helpful?

Solution

image1.png must be in the current directory of the running Python program, or be given as a relative path to the current directory of the running program, or less portable, but probably easier to make work, it can be given as an absolute path.

In particular, I think you may find the answer given in this post most helpfull: Python's working directory when running with WSGI and Apache (for dynamically figuring out the absolute path to image.png.

OTHER TIPS

The python-docx module has changed somewhat since the code written above. Now, to add an image in django would be something like this:

from docx import *
from docx.shared import Inches
document = Document()
document.add_picture((r'%s/static/images/my-header.png' % (settings.PROJECT_PATH)), width=Inches(4))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top