Search code examples
pythondjangopdfreportlabbytesio

How to add PDF file created with BytesIO into a FileField in a model of Django


I can create a PDF file using reportlab in a Django application. However, I can't add it into a FileField in a model. I wonder how to transfer an io.BytesIO data into FileField in Django.

This is summary of my views.py.

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.pdfbase import pdfmetrics

buffer = io.BytesIO()
cc = canvas.Canvas(buffer, pagesize=A4)

# describe something
font_name = "HeiseiKakuGo-W5"
cc.registerFont(UnicodeCIDFont(font_name))
cc.setFont(font_name, 7)
cc.drawString(65*mm, 11*mm, 'test')

cc.showPage()
cc.save()
buffer.seek(0)

exampleObject= get_object_or_404(SomeModel, pk=self.kwargs['pk'])
exampleObject.exampleFileField.save('test.pdf', File(buffer)) # here! this sentence doesn't work.
exampleObject.save()

return FileResponse(buffer, as_attachment=True, filename='test.pdf')

The point is the sentence below doesn't work. I think "File(buffer)" is not appropliate.

exampleObject.exampleFileField.save('test.pdf', File(buffer))

Although once I tried to save a pdf into a FileField after creating a pdf file in a directory as a temporaly file, I prefer to do it by using io.BytesIO.


Solution

  • I believe your missing buffer.get_value()

    I also use ContentFile instead of File though not sure it's necessary.

    I just tested the following snippet and it works using reportlab==3.5.32

    import io
    
    from django.core.files.base import ContentFile
    from reportlab.lib.pagesizes import A4
    from reportlab.pdfgen import canvas
    
    from my_app.models import MyModel
    
    buffer = io.BytesIO()
    canv = canvas.Canvas(buffer, pagesize=A4)
    canv.drawString(100, 400, "test")
    canv.save()
    pdf = buffer.getvalue()
    buffer.close()
    
    my_object = MyModel.objects.latest("id")
    my_object.file_field.save("test.pdf", ContentFile(pdf))