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 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 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
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'].
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')
...
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'))