I have been following this tutorial which helped me in generating pdf files in Django using xhtml2pdf. Now what I want is to save the generated file to disk without having to prompt the user to download the file.
Below is the code I am using to generate the pdf file in utils.py file and views.py file.
#utils.py file
from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
#views.py snippet of code
html = template.render(context)
pdf = render_to_pdf('tdn.html', context)
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
filename = "TDN_%s.pdf" %("12341231")
content = "inline; filename='%s'" %(filename)
download = request.GET.get("download")
if download:
content = "attachment; filename='%s'" %(filename)
response['Content-Disposition'] = content
TDN.objects.filter(id=tdn_no).update(printed=1)
return response
return HttpResponse("Not found")
Any pointers on how I can write to disk the generated pdf will be greatly appreciated
Tried this?
with open('mypdf.pdf', 'wb+') as output:
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("UTF-8")), output)
If you want to save it to ImageField use ContentFile in Django!
Related
I have django a view that exports records using the xhtml2pdf library, however I have observed that the view keeps refreshing several times as my pdf function processes the request. Also, this behavior keeps reloading the view for a number of times until the file is ready for export. This is potentially harmful since the view queries data in bulk to be loaded onto the pdf.
The error I am getting from the terminal is:
Broken pipe from ('127.0.0.1', 1314)
I read somewhere that this could be as a result of the browser closing and opening the connection but I tested on another view loading a page and delayed the response but it did not happen as above.
This is my views.py:
#login_required(login_url='/')
#user_passes_test(validate_all_view())
def export_assets(request):
if request.method == 'POST':
checkbox_list = request.POST.getlist('id[]')
if not len(checkbox_list) > 0:
messages.error(request, "You must select at least one row to export.")
return redirect('view_active_assets')
queryset = Assets.objects.filter(id__in=checkbox_list)[:10000]
if 'excel' in request.POST:
return process_excel_export(queryset)
if 'pdf' in request.POST:
return process_pdf_export(request, queryset)
else:
return redirect('view_active_assets')
render function:
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
Process pdf function:
def process_pdf_export(request, queryset):
domain = settings.DOMAIN
context = {'queryset': queryset, 'asset_count': queryset.count()}
pdf = render_to_pdf('dashboard/pdf_templates/assets_pdf.html', context)
response = HttpResponse(pdf, content_type='application/pdf')
filename = "Assets Export.pdf"
content = "inline; filename=%s" % (filename)
download = request.GET.get("download")
if download:
content = "attachment; filename='%s'" % (filename)
response['Content-Disposition'] = content
return response
i have an app in django that do some processes and build a file, in one section, i want to show the user that file to download that.
(for example, user enter a name in front-end and the app give him a pdf file to download).
the file building process is ok and it is in /app_dir/media/app/report/username/file.pdf
here is my code, but it does not worked and i faced some problems.
can you please help me, where is my problem?
and how i can make that user-specefic? each user just can access to his files.
views.py (my_main_function):
#login_required(login_url='/login/')
def my_function(request):
if request.method == 'GET':
return render(request, 'app/my_function.html')
else:
try:
#my main process to build .PDF file
except ValueError:
return render(request, 'app/dashboard.html', {'error':'Bad data passed in. Try again.'})
return render(request, 'app/download.html')
views.py (download function):
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
# Define the full file path
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# Open the file for reading content
path = open(filepath, 'rb')
path.read()
# Set the return value of the HttpResponse
response = HttpResponse(path, content_type='application/pdf')
# Set the HTTP header for sending to browser
response['Content-Disposition'] = "attachment; filename=%s" % filepath
# Return the response value
return response
urls.py:
path('download/', views.download_file, name='download_file'),
simple testing download.html file:
<html>
<title>Download File</title>
</head>
<body>
<enter>
<h1>Download File using link</h1>
Download PDF
</center>
</body>
</html>
It is not clear what problems you have encountered, but there are some lines I would correct in your code
# first of all why not use django.http.FileResponse instead of HttpResponse?
# https://docs.djangoproject.com/en/3.2/ref/request-response/#fileresponse-objects
from django.http import FileResponse
# if you want files to be accessible only to owners
# you probably should force user to login before download
#login_required
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# somewhere here you need to check if user has access to the file
# if files ownership based solely on {user_name} dir in filesystem
# then it is enough to check if file exists
if os.path.exists(filepath):
response = FileResponse(open(filepath, 'rb'))
# it is probably better to use filename instead of filepath
response['Content-Disposition'] = "attachment; filename=%s" % filename
return response
else:
raise Http404
I wrote a really simple django project to test xlsxwriter. I can open the excel file, but when I name the file 'filename.xlsx', the file is downloaded as 'filename.xlsx.xls'. How can I fix this?
from django.shortcuts import render
from django.http import HttpResponse
from .excel import get_excel
def home_view(request):
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=filename.xlsx'
excel_data = get_excel()
response.write(excel_data)
return response
XSLX is an OpenXML format, so the mimetype is different, it uses:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
you thus should change this to:
def home_view(request):
response = HttpResponse(
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
response['Content-Disposition'] = 'attachment; filename=filename.xlsx'
excel_data = get_excel()
response.write(excel_data)
return response
I followed this coadingforentrepreneurs tutorial to generate pdfs and it works fine.
The issue is when i use a post request to generate a pdf it shows me a 405 error. I am using post method to access customer-id to generate a invoice.
Here is my GeneratePDF class
class GeneratePDF(View):
def get(self, request, *args, **kwargs):
if request.method == 'POST':
template = get_template('head/invoice.html')
context = {
"customer":"aaaa"
}
html = template.render(context)
pdf = render_to_pdf('head/invoice.html', context)
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
filename = "Invoice_%s.pdf" %("12341231")
content = "inline; filename='%s'" %(filename)
download = request.GET.get("download")
if download:
content = "attachment; filename='%s'" %(filename)
response['Content-Disposition'] = content
return response
template = get_template('head/invoice.html')
context = {
"customer":"aaaa"
}
html = template.render(context)
pdf = render_to_pdf('head/invoice.html', context)
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
filename = "Invoice_%s.pdf" %("12341231")
content = "inline; filename='%s'" %(filename)
download = request.GET.get("download")
if download:
content = "attachment; filename='%s'" %(filename)
response['Content-Disposition'] = content
return response
I have not edited any other files
Here is the response from the server
Method Not Allowed (POST): /employee/customer_printbill/
Method Not Allowed: /employee/customer_printbill/
I am a beginner in django and i am unable to resolve this issue. Please help me out.
You're mixing function based and class based views. You should define post method in your class based view, and request will be dispatched to that post method. And thus you do not need to check if request.method is POST in your get method, because POST request will be handled by your post method. Please see Django Docs for more info.
I am using html2pdf to generate pdf reports, which does not generate pdf if there is large volume of data/records. I have 5000 records & it will covers 400+ pdfs pages. If the data/records are only 1000(covers up-to 80-85 pdf pages), it generated successfully. But for above that its failing completely. Is there any solution or should I need to use any other plugins.
I uses write_pdf function
html2pdf.py
from django import http
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template.loader import get_template
from django.template import Context
import ho.pisa as pisa
import cStringIO as StringIO
import cgi, os
from django.conf import settings
from datetime import datetime
def fetch_resources(uri, rel):
path = os.path.join(settings.MEDIA_ROOT, uri.replace("//", ""))
return path
def write_pdf(template_src, context_dict, filename):
os.chdir(settings.MEDIA_ROOT+'/pathtofoldertosave/')
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = open(filename, 'wb')
pdf = pisa.pisaDocument(StringIO.StringIO(
html.encode("UTF-8")), result,link_callback=fetch_resources)
result.close()
return str(settings.MEDIA_URL)+'/pathtofoldertosave/'+str(filename)
def render_to_pdf(template_src, context_dict,file_name):
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result, link_callback=fetch_resources)
if not pdf.err:
response = HttpResponse( result.getvalue() ) response['Content-Type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment; filename='+file_name;
return response
return http.HttpResponse('We had some errors<pre>%s</pre>' % cgi.escape(html))
Function for generating report is: report.py
def reportFun(request):
mem = Member.objects.all()
FileName = "Report_"+datetime.now().strftime('%d-%m-%Y-%H:%M')+".pdf"
fname = "http://"+str(request.META['HTTP_HOST'])+"/"+write_pdf('report_pdf.html',{'pagesize':'A4','data':mem}, FileName)
return render_to_response("report.html",{'result':mem,'fname':fname}, context_instance=RequestContext(request))