Preview PDF document - django

If I run:
127.0.0.1:8000/document/1/preview
this pdf file is downloaded.
I need display it in HTML(preview with print function). How to do it?
views.py
from xhtml2pdf import pisa
from django.template.loader import render_to_string
from datetime import datetime
import StringIO
def pdf_report(request, did):
d_instance = get_object_or_404(MyObject, pk=did, user=request.user)
contents = render_to_string('pdf_preview.html', {'object':d_instance})
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=answer_%s.pdf' % (f_date,)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(contents.encode('utf-8')), result, show_error_as_pdf=True, encoding='UTF-8')
if not pdf.err:
response.write(result.getvalue())
result.close()
return response
urls.py
(r'^document/(?P<did>\d+)/preview/$', 'app.views.pdf_report'),

To make the file open in the browser, use inline content-disposition.
response['Content-Disposition'] = 'inline; filename=answer_%s.pdf' % f_date

Related

While converting HTML to pdf, the page is stuck in loading at create pdf

While trying to generate a pdf file with the below code, the browser is stuck loading
from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf.pisa import pisa
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
print('RESULT')
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
print('PDF')
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
and generate_pdf view:
def generate_pdf(request):
pdf = render_to_pdf('doc.html')
response = HttpResponse(pdf, content_type='application/pdf')
filename = "Document_to_mail.pdf"
content = "inline; filename=%s" %(filename)
download = request.GET.get("download")
if download:
content = "attachment; filename=%s" %(filename)
response['Content-Disposition'] = content
return response
browser is stuck in pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)

pdfkit django in digitalocean

pdfkit works in the local machine everything works successfully displays as pdf, but in digitalocean sends to the server error 500, why?
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.template.loader import get_template
import pdfkit
from .models import Buses
def pdf(request, id):
bus = Buses.objects.get(id=id)
template = get_template('buses/pdf.html')
html = template.render({'bus': bus})
options = {
'page-size': 'Letter',
'encoding': "UTF-8",
}
pdf = pdfkit.from_string(html, False, options)
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="{}_{}.pdf"'.format(bus.company, bus.name)
return response
If your template references other files, you may need to set 'enable-local-file-access': True in your options.
See: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4460
I am not sure but your problem could be the location of wkhtmltopdf
It is always a better option to specify the wkhtmltopdf location. So on your digital ocean server - start by installing wkhtmltopdf - if you dont have it yet.
This is a great tutorial to use for any version of Ubuntu - https://computingforgeeks.com/install-wkhtmltopdf-on-ubuntu-debian-linux/
Then on your command line:
which wkhtmltopdf
Note the location, your code will then look like this:
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.template.loader import get_template
import pdfkit
from .models import Buses
def pdf(request, id):
bus = Buses.objects.get(id=id)
template = get_template('buses/pdf.html')
html = template.render({'bus': bus})
options = {
'page-size': 'Letter',
'encoding': "UTF-8",
}
config = pdfkit.configuration(wkhtmltopdf='/usr/local/bin/wkhtmltopdf') #use your actual location here
pdf = pdfkit.from_string(html, False, configuration=config, options=options)
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="{}_{}.pdf"'.format(bus.company, bus.name)
return response

How to generate a file upload (test) request with Django REST Framework's APIRequestFactory?

I have developed an API (Python 3.5, Django 1.10, DRF 3.4.2) that uploads a video file to my media path when I request it from my UI. That part is working fine. I try to write a test for this feature but cannot get it to run successfully.
#views.py
import os
from rest_framework import views, parsers, response
from django.conf import settings
class FileUploadView(views.APIView):
parser_classes = (parsers.FileUploadParser,)
def put(self, request, filename):
file = request.data['file']
handle_uploaded_file(file, filename)
return response.Response(status=204)
def handle_uploaded_file(file, filename):
dir_name = settings.MEDIA_ROOT + '/scene/' + filename + '/cam1'
new_filename = 'orig.mp4'
if not os.path.exists(dir_name):
os.makedirs(dir_name)
file_path = os.path.join(dir_name, new_filename)
with open(file_path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
and
#test.py
import tempfile
import os
from django.test import TestCase
from django.conf import settings
from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from rest_framework.test import APIRequestFactory
from myapp.views import FileUploadView
class UploadVideoTestCase(TestCase):
def setUp(self):
settings.MEDIA_ROOT = tempfile.mkdtemp(suffix=None, prefix=None, dir=None)
def test_video_uploaded(self):
"""Video uploaded"""
filename = 'vid'
file = File(open('media/testfiles/vid.mp4', 'rb'))
uploaded_file = SimpleUploadedFile(filename, file.read(), 'video')
factory = APIRequestFactory()
request = factory.put('file_upload/'+filename,
{'file': uploaded_file}, format='multipart')
view = FileUploadView.as_view()
response = view(request, filename)
print(response)
dir_name = settings.MEDIA_ROOT + '/scene/' + filename + '/cam1'
new_filename = 'orig.mp4'
file_path = os.path.join(dir_name, new_filename)
self.assertTrue(os.path.exists(file_path))
In this test, I need to use an existing video file ('media/testfiles/vid.mp4') and upload it since I need to test some processings on the video data after: that's why I reset the MEDIA_ROOT using mkdtemp.
The test fails since the file is not uploaded. In the def put of my views.py, when I print request I get <rest_framework.request.Request object at 0x10f25f048> and when I print request.data I get nothing. But if I remove the FileUploadParser in my view and use request = factory.put('file_upload/' + filename, {'filename': filename}, format="multipart") in my test, I get <QueryDict: {'filename': ['vid']}> when I print request.data.
So my conclusion is that the request I generate with APIRequestFactory is incorrect. The FileUploadParseris not able to retrieve the raw file from it.
Hence my question: How to generate a file upload (test) request with Django REST Framework's APIRequestFactory?
Several people have asked questions close to this one on SO but I had no success with the proposed answers.
Any help on that matter will be much appreciated!
It's alright now! Switching from APIRequestFactory to APIClient, I managed to have my test running.
My new test.py:
import os
import tempfile
from django.conf import settings
from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
from django.contrib.auth.models import User
class UploadVideoTestCase(APITestCase):
def setUp(self):
settings.MEDIA_ROOT = tempfile.mkdtemp()
User.objects.create_user('michel')
def test_video_uploaded(self):
"""Video uploaded"""
filename = 'vid'
file = File(open('media/testfiles/vid.mp4', 'rb'))
uploaded_file = SimpleUploadedFile(filename, file.read(),
content_type='multipart/form-data')
client = APIClient()
user = User.objects.get(username='michel')
client.force_authenticate(user=user)
url = reverse('file_upload:upload_view', kwargs={'filename': filename})
client.put(url, {'file': uploaded_file}, format='multipart')
dir_name = settings.MEDIA_ROOT + '/scene/' + filename + '/cam1'
new_filename = 'orig.mp4'
file_path = os.path.join(dir_name, new_filename)
self.assertTrue(os.path.exists(file_path))
Below, testing file upload using APIRequestFactory as requested (and ModelViewSet).
from rest_framework.test import APIRequestFactory, APITestCase
from my_project.api.views import MyViewSet
from io import BytesIO
class MyTestCase(APITestCase):
def setUp(self):
fd = BytesIO(b'Test File content') # in-memory file to upload
fd.seek(0) # not needed here, but to remember after writing to fd
reqfactory = APIRequestFactory() # initialize in setUp if used by more tests
view = MyViewSet({'post': 'create'}) # for ViewSet {action:method} needed, for View, not.
request = factory.post('/api/new_file/',
{
"title": 'test file',
"fits_file": self.fd,
},
format='multipart') # multipart is default, but for clarification that not json
response = view(request)
response.render()
self.assertEqual(response.status_code, 201)
Note that there is no authorization for clarity, as with: 'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'].

How to save response to file?

on serverside I have function which generate pdf document:
def get_pdf(template, context_dict):
context = Context(context_dict)
html = template.render(context)
import subprocess
wkhtml2pdf = subprocess.Popen((settings.WKHTML2PDF_COMMAND,
"--encoding",
"UTF-8",
"-",
"-"),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
wkdata = wkhtml2pdf.communicate(html.encode('utf8'))
pdf = wkdata[0];
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=%s.pdf' % (
timezone.now().strftime('%Y_%m_%d_%H_%M_%S')
)
response.write(pdf)
return response
And I want to save this file on serverside before return response. How to do it?
Where do you want to save this file? I suppose that in the MEDIA_ROOT:
import os
from django.conf import settings
...
pdf = wkdata[0];
file_name = os.path.join(settings.MEDIA_ROOT,
timezone.now().strftime('%Y_%m_%d_%H_%M_%S.pdf'))
with open(file_name, 'w') as f:
f.write(pdf)
response = HttpResponse(mimetype='application/pdf')
...

download images through django

I try to download an image from my django website. I do it like this:
def file_download(request, filename):
from django.core.servers.basehttp import FileWrapper
import mimetypes
import settings
import os
filepath = os.path.join(settings.MEDIA_ROOT, filename)
wrapper = FileWrapper(open(filepath))
content_type = mimetypes.guess_type(filepath)[0]
response = HttpResponse(wrapper, mimetype='content_type')
response['Content-Disposition'] = "attachment; filename=%s" % filename
return response
However, it doesn't work for images (I tries jpg files), but do work for txt files. Why?
Probably you need to open the file in binary mode:
wrapper = FileWrapper(open(filepath, 'rb'))