For a few days Ive been trying to get this working and, while I think im getting close, I still havent got it working yet.
I have a function which uses ReportLab to generate a SimpleDocTemplate pdf and I want to return it to the calling view so I can save it to the uesrs Profile model.
This is my code so far:
model.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pdf = models.FileField(upload_to='pdfs/user_pdfs')
the error message:
'HttpResponse' object has no attribute 'read'
view
def final_question(request):
if request.method == 'POST':
# this is the final form they complete
form = FinalQuestionForm(request.POST, request.FILES, instance=request.user.finalquestion)
if form.is_valid():
form.save()
# generate pdf containing all answers to enrolment questions
users_pdf = utils.generate_user_pdf(request)
# here i get the users model
# hard coded user_id for testing
users_profile = Profile.objects.get(user_id=1)
# then i get the field I want to save to
pdf = users_profile.profile_pdf
# then i save the generated pdf to the field
pdf.save('user_1_pdf', users_pdf)
my pdf generation function
def generate_user_pdf(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename = "test.pdf"'
doc = SimpleDocTemplate(response)
elements = []
data= [
['---TEST DATA---'],
['test data'],
]
[.. cont ..]
doc.build(elements)
return response
Thank you.
--EDIT--
error:
argument should be a bytes-like object or ASCII string, not 'FileResponse'
utils:
def generate_pdf(request):
buffer = io.BytesIO()
doc = SimpleDocTemplate('test')
story = []
doc.build(story)
response = FileResponse(buffer.getvalue())
return response
views.py
# generate pdf containing all answers
user_pdf = utils.generate_pdf(request)
# get users enrolment_pdf field
# temp hard-coded
user_profile = Profile.objects.get(user_id=1)
field = user_profile.user_pdf
# save the generated pdf to the user in the database
file_data = ContentFile(base64.b64decode(user_pdf))
field.save('test', file_data)
Thank you
Firstly, there is an answer.
In addition to this answers, you need to read this, just work with buffer.getvalue()
bytes array and use ContentFile
class to save this to model field.
To simplify your work with Response object, use FileResponse.
--EDIT--
You need to write your pdf to buffer:
doc = SimpleDocTemplate(buffer)
doc.build(story)
buffer.seek(0)
pdf: bytes = buffer.getvalue()
return FileResponse(pdf, filename='doc.pdf')
And, I've found these instructions in docs.
To save pdf into Profile
:
file_data = ContentFile(pdf)
profile = Profile.objects.get(...)
profile.pdf_field.save('filename.pdf', file_data, save=False)
profile.save()