the filename of pdf file doesnt work correctly with wkhtmltopdf - django

I have a button download in my Django project, where I can export the report for a certain date in a pdf format. Everything works fine on my laptop with Linux, but when I set the project in the local server of our company, the name of the file is showing without a date.
Here is my code:
template_name = 'pdf.html'
template = get_template(template_name)
html = template.render({"data": data, "date":date, "index":index})
if 'DYNO' in os.environ:
print('loading wkhtmltopdf path on heroku')
WKHTMLTOPDF_CMD = subprocess.Popen(
['which', os.environ.get('WKHTMLTOPDF_BINARY', 'wkhtmltopdf-pack')],
stdout=subprocess.PIPE).communicate()[0].strip()
else:
print('loading wkhtmltopdf path on localhost')
WKHTMLTOPDF_CMD = ('/usr/local/bin/wkhtmltopdf/bin/wkhtmltopdf')
config = pdfkit.configuration(wkhtmltopdf=WKHTMLTOPDF_CMD)
options = {
'margin-bottom': '10mm',
'footer-center': '[page]'
}
pdf = pdfkit.from_string(html, False, configuration=config, options=options)
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="otchet-{}.pdf"'.format(date)
return response
when I download locally, the name of the file is - otchet-2021-06-30.pdf
but on server, it looks like - otchet%20.pdf
I have no idea, how to fix it...

Just a thought. Use an f string.
response['Content-Disposition'] = f'attachment; filename="otchet-{date}.pdf"'

Related

Return Zip file with HttpResponse using StringIO, Django, Python

I'm trying to return a zip file with HttpResponse, using StringIO() because i'm not storing in DB or Harddrive.
My issue is that my response is returning 200 when i request the file, but the OS never ask me if i want to save the file, or the file is never saved. i think that the browser is reciving the file because i have seen on the Network Activity (inspect panel) and it says than a 6.4 MB file type zip is returned.
I'm taking a .step file (text file) from a DB's url, extracting the content, zipping and returning, that's all.
this my code:
def function(request, url_file = None):
#retrieving info
name_file = url_file.split('/')[-1]
file_content = urllib2.urlopen(url_file).read()
stream_content = StringIO(file_content)
upload_name = name_file.split('.')[0]
# Create a new stream and write to it
write_stream = StringIO()
zip_file = ZipFile(write_stream, "w")
try:
zip_file.writestr(name_file, stream_content.getvalue().encode('utf-8'))
except:
zip_file.writestr(name_file, stream_content.getvalue().encode('utf-8', 'ignore'))
zip_file.close()
response = HttpResponse(write_stream.getvalue(), mimetype="application/x-zip-compressed")
response['Content-Disposition'] = 'attachment; filename=%s.zip' % upload_name
response['Content-Language'] = 'en'
response['Content-Length'] = write_stream.tell()
return response

Files downloaded from django don't have file's extension

I'm writing a view on my Django 1.5 progect that make the user download a file.
This is the code:
import mimetypes
from django.http import HttpResponse
def filedownload(request, file_name):
down_file = File.objects.get(name = file_name)
file_path = MEDIA_ROOT+str(down_file.file) #down_file.file is something like folder/name_file.extension
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % file_name
response['X-Sendfile'] = file_path
return response
It work just fine but the file is downloaded without the extension. Why? How can I solve this? I know that I can let the webserver do this but it's a dummy project and has to works only in Django.
EDIT:
I solved thanks the answer of sk1p and using a more elaborate code found here
You are specifying the filename to be displayed in the browser with this line:
response['Content-Disposition'] = 'attachment; filename=%s' % file_name
so if file_name doesn't contain the extension, the download won't either. So: make sure the Content-Disposition header contains the right filename and extension!

How to serve a django-webodt file to users?

I'm trying to allow users to export some of their database data. I am using django-webodt to create a .odt file from their data. I then am trying to allow them to download it. The file is created just fine, but when it downloads it seems to download a blank file. I think there is some difference between where the server is looking for the file and where it actually is. I was wondering how to get this to work properly? I'm relatively new to django so any help would be appreciated. The code I have is below:
def downloadBook(request, val):
template = webodt.ODFTemplate('conversion.odt')
context = dict(ideas=Book.objects.getIdeaSet(int(val)))
document = template.render(Context(context))
file_name = os.path.basename(document.name)
path_to_file = os.path.dirname(document.name)
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
return response
I did the following and it works:
from django.template import Context
from webodt import ODFTemplate
template = ODFTemplate('template_file.odt')
context = { 'some_dict': '' }
document = template.render(Context(context))
response = HttpResponse(document.read(), mimetype='application/vnd.oasis.opendocument.text')
response['Content-Disposition'] = "attachment; filename=fancy-filename-as-you-like.odt"
document.close() # delete the document on /tmp
return response

returning zip for download from view in django

I try to download a zip file in my Django application.
How should I return it from the view?
I tried the code below, but I get some kind of alert in the browser with the content of the file inside my zip.
What am I doing wrong?
def download_logs(request):
date = datetime.datetime.now().__str__().replace(" ", "_").split(".")[0]
os.system("df -h . > /tmp/disk_space")
response = HttpResponse(mimetype='application/zip')
response['Content-Disposition'] = 'filename=logs_%s.zip' % date
files = []
files.append("/tmp/disk_space")
buffer = StringIO()
zip = zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED)
for name in files:
file = open(name, "r")
zip.writestr(name, file.read())
file.close()
zip.close()
buffer.flush()
ret_zip = buffer.getvalue()
buffer.close()
response.write(ret_zip)
return response
You should tell the browser to treat the response as a file attachment.
From the docs, you should do something like:
>> response = HttpResponse(my_data, mimetype='application/vnd.ms-excel')
>>> response['Content-Disposition'] = 'attachment; filename=foo.xls'
Here is a link to actual working code for building a ZipFile in memory and returning it to the user as a file to download: django-rosetta's view.py

rendering a ReportLab pdf built from SimpleDocTemplate

I've a got a django app that currently generates pdfs using a canvas that the user can download. I create a StringIO buffer, do some stuff and then send call response.write.
# Set up response
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=menu-%s.pdf' % str(menu_id)
# buffer
buff = StringIO()
# Create the pdf object
p = canvas.Canvas(buff)
# Add some elements... then
p.showPage()
p.save()
# Get the pdf from the buffer and return the response
pdf = buff.getvalue()
buff.close()
response.write(pdf)
I now want to build my pdf using platypus and SimpleDocTemplate and have written this
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
menu_pdf = SimpleDocTemplate(pdf_name, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(menu_pdf)
return response
But this doesn't work, it creates a bad pdf that cannot be opened. I presume the line
response.write(menu_pdf)
is incorrect.
How do I render the pdf?
Your error is actually a pretty simple one. It's just a matter of trying to write the wrong thing. In your code, menu_pdf is not a PDF, but a SimpleDocTemplate, and the PDF has been stored in pdf_name, although here I suspect pdf_name is a path name rather than a file object. To fix it, change your code to use a memory file like you did in your original code:
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
buff = StringIO()
menu_pdf = SimpleDocTemplate(buff, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(buff.getvalue())
buff.close()
return response
I'm not sure if using file objects rather than paths with Platypus is mentioned in the documentation, but if you dig into the code you'll see that it is possible.
For people who are working with python3 and django 1.7+ some changes to the answer need to be done.
from django.shortcuts import HttpResponse
import io
from reportlab.platypus import SimpleDocTemplate, BaseDocTemplate
def view(request):
buffer = io.BytesIO()
doc = # ... create your SimpleDocTemplate / BaseDocTemplate
# create the usual story
story = []
# ...
doc.build(story)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_name.pdf'
response.write(buffer.getvalue())
buffer.close()
return response