0

Here's my use case. I have a rental contract template (.docx file). I want to populate the fields of this contract by pulling data from my models and injecting them into the template (using Jinja tags), then save the output file directly to the database. So far so good.

My problem is that I currently do this as a two step process; 1) open template, populate and save as new file; 2) upload the file as a FileField to my Model, thereby creating a duplicate...

Is there a way for me to create and store the formatted file without first having to save it? (thus avoiding duplicates)

According to this thread, the suggested approach is to use django.core.files.base.ContentFile and pass the content of the file as a string, like so.

self.lease_draft.save("Name of the file", ContentFile("A string with the file content"))

My problem is that ContentFile() only accepts strings or bytes as parameters. My input is a populated .docx file (DocxTemplate object), not a string.

Any suggestions on how to approach this?

Models.py

class Booking(models.Model):
    lease_draft = models.FileField(upload_to='lease_drafts/', null=True)

Views.py

from django.core.files.base import ContentFile
from docxtpl import DocxTemplate

def populate_docx(self, template_path, context):

        draft_lease = DocxTemplate(template_path) /// Gets the template
        draft_lease.render(context) /// Populates the template

        self.lease_draft.save('Lease #12345', ContentFile(draft_lease)) /// Save the populated file (throws an error)

Error

TypeError: a bytes-like object is required, not 'DocxTemplate'
Max Vallee
  • 406
  • 5
  • 15

1 Answers1

1

I am assuming you are using docxtpl and python docx. docx can save in byte like objects.
Something like this should work:

import io
def populate_docx(self, template_path, context):
        
        draft_lease = DocxTemplate(template_path) /// Gets the template
        draft_lease.render(context) /// Populates the template
        file_bytes = io.BytesIO()
        draft_lease.save(file_bytes)
        file_bytes.seek(0)
        self.lease_draft.save('Lease #12345', ContentFile(file_bytes.read()))
Max Vallee
  • 406
  • 5
  • 15
Abdul Aziz Barkat
  • 19,475
  • 3
  • 20
  • 33