python html2pdf not generating pdf for bulk data - python

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))

Related

Remove .xls extension on excel file created with xlsxwriter on django

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

django: unexpected file download after redirect when file does not exist

Django==1.11.12
If the file exists, the view function creates StreamingHttpResponse and all is fine. But if the file does not exist, the view function should redirect. The problem is, it does not redirect but instead prompt up to ask to save as a file, which has the content of redirected html.
import os
from wsgiref.util import FileWrapper
import mimetypes
from django.http import StreamingHttpResponse
from django.shortcuts import render, redirect
def download(request, file_path):
try:
response = StreamingHttpResponse(
FileWrapper(open(file_path, 'rb'), chunk_size),
content_type=mimetypes.guess_type(file_path)[0])
response['Content-Length'] = os.path.getsize(file_path)
response['Content-Disposition'] = "attachment; filename=a_file.xlsx")
except FileNotFoundError as e:
response = redirect("home")
return response
It turns out that the problem lays in template, where the download link is <a href="xxx" download> and the download attribute force the download.

Django - Save to disk a pdf file generated using xhtml2pdf

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!

How to upload a file and return JSON response in same click

My code for upload in views.py is
def upload(request):
context = {}
if request.method == 'POST':
uploaded_file = request.FILES['document']
timestr = time.strftime("%Y%m%d-%H%M%S")
fs = FileSystemStorage()
uploaded_file.name = timestr+"_"+uploaded_file.name
name = fs.save(uploaded_file.name, uploaded_file)
context['url'] = fs.url(name)
return render(request, 'upload.html', context)
And my HTML webpage looks like this:
I am building an API and want to return JSON response when a user clicks on the upload button after choosing their file. I am using Django and new to web development.
You can return JSON response in three different ways in Django.
HttpResponse()
# using pure Django
from django.http import HttpResponse
return HttpResponse(json.dumps(context), content_type="application/json")
JsonResponse()
# using pure Django
from django.http import JsonResponse
return JsonResponse(context)
Response()
# using Django Rest Framework
from rest_framework.response import Response
return Response(context)

How to return generated file download with Django REST Framework?

I need to return generated file download as a Django REST Framework response. I tried the following:
def retrieve(self, request, *args, **kwargs):
template = webodt.ODFTemplate('test.odt')
queryset = Pupils.objects.get(id=kwargs['pk'])
serializer = StudentSerializer(queryset)
context = dict(serializer.data)
document = template.render(Context(context))
doc = converter().convert(document, format='doc')
res = HttpResponse(
FileWrapper(doc),
content_type='application/msword'
)
res['Content-Disposition'] = u'attachment; filename="%s_%s.zip"' % (context[u'surname'], context[u'name'])
return res
But it returns a msword document as json.
How do I make it start downloading as file instead?
Here's an example of returning a file download directly from DRF. The trick is to use a custom renderer so you can return a Response directly from the view:
from django.http import FileResponse
from rest_framework import viewsets, renderers
from rest_framework.decorators import action
class PassthroughRenderer(renderers.BaseRenderer):
"""
Return data as-is. View should supply a Response.
"""
media_type = ''
format = ''
def render(self, data, accepted_media_type=None, renderer_context=None):
return data
class ExampleViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Example.objects.all()
#action(methods=['get'], detail=True, renderer_classes=(PassthroughRenderer,))
def download(self, *args, **kwargs):
instance = self.get_object()
# get an open file handle (I'm just using a file attached to the model for this example):
file_handle = instance.file.open()
# send file
response = FileResponse(file_handle, content_type='whatever')
response['Content-Length'] = instance.file.size
response['Content-Disposition'] = 'attachment; filename="%s"' % instance.file.name
return response
Note I'm using a custom endpoint download instead of the default endpoint retrieve, because that makes it easy to override the renderer just for this endpoint instead of for the whole viewset -- and it tends to make sense for list and detail to return regular JSON anyway. If you wanted to selectively return a file download you could add more logic to the custom renderer.
This may work for you:
file_path = file_url
FilePointer = open(file_path,"r")
response = HttpResponse(FilePointer,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response.
For FrontEnd code refer this
I am using DRF and i found a view code to download file, which would be like
from rest_framework import generics
from django.http import HttpResponse
from wsgiref.util import FileWrapper
class FileDownloadListAPIView(generics.ListAPIView):
def get(self, request, id, format=None):
queryset = Example.objects.get(id=id)
file_handle = queryset.file.path
document = open(file_handle, 'rb')
response = HttpResponse(FileWrapper(document), content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename="%s"' % queryset.file.name
return response
and url.py will be
path('download/<int:id>/',FileDownloadListAPIView.as_view())
I am using React.js in frontend and i get a response like
handleDownload(id, filename) {
fetch(`http://127.0.0.1:8000/example/download/${id}/`).then(
response => {
response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
console.log(url);
a.href = url;
a.download = filename;
a.click();
});
});
}
and after i got successful in downloading a file which also opens correctly and i hope this gonna work. Thanks
For me, using Python 3.6, Django 3.0, and DRF 3.10, The problem came from using the wrong type of response. I needed to use a django.http.HttpResponse, as seen below:
from django.http import HttpResponse
...
with open('file.csv', 'r') as file:
response = HttpResponse(file, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=file.csv'
return response
I solved my problem by saving file in media folder and sending of the link of it to front-end.
#permission_classes((permissions.IsAdminUser,))
class StudentDocxViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
def retrieve(self, request, *args, **kwargs):
template = webodt.ODFTemplate('test.odt')
queryset = Pupils.objects.get(id=kwargs['pk'])
serializer = StudentSerializer(queryset)
context = dict(serializer.data)
document = template.render(Context(context))
doc = converter().convert(document, format='doc')
p = u'docs/cards/%s/%s_%s.doc' % (datetime.now().date(), context[u'surname'], context[u'name'])
path = default_storage.save(p, doc)
return response.Response(u'/media/' + path)
And handled this like in my front-end (AngularJS SPA)
$http(req).success(function (url) {
console.log(url);
window.location = url;
})
In models.py
class Attachment(models.Model):
file = models.FileField(upload_to=attachment_directory_path, blank=True, null=True)
...
#property
def filename(self):
return self.file.name.split('/')[-1:][0]
in views.py
import mimetypes
from django.http import FileResponse
class AttachmentViewSet(ModelViewSet):
...
#action(methods=['GET'], detail=True)
def download(self, request, **kwargs):
att = self.get_object()
file_handle = att.file.open()
mimetype, _ = mimetypes.guess_type(att.file.path)
response = FileResponse(file_handle, content_type=mimetype)
response['Content-Length'] = att.file.size
response['Content-Disposition'] = "attachment; filename={}".format(att.filename)
return response
and in frontend, I used axios for download files. api is axios client.
export function fileDownload(url, filename){
return api.get(url, { responseType: 'blob' })
.then((response)=>{
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
})
}
hope that it helps
Using django-downloadview this can be done like so:
from rest_framework.decorators import action
from django_downloadview import ObjectDownloadView
class DocumentViewSet(viewsets.ReadOnlyModelViewSet):
#action(detail=True)
def download(self, request, pk):
return ObjectDownloadView.as_view(
model=, # your model here
)(request, pk=pk)
The viewset can then be registered via DRF routers.

Categories

Resources