Serving a django static text file - python

I have a text file in the static folder in my project root.
I'd like to serve it so I've created:
#csrf_exempt
def display_text(request):
content =
return HttpResponse(content, content_type='text/plain; charset=utf8')
How do I set the path to the textfile, or how do I read it in to 'content', so that I can display it.

Have a look at this question that lets Apache handle the file delivery with mod_xsendfile.
If you insist on having Django itself delivering the file, you could do the following:
from django.http import StreamingHttpResponse
#csrf_exempt
def display_text(request):
content = open('/your/file', 'r').read()
response = StreamingHttpResponse(content)
response['Content-Type'] = 'text/plain; charset=utf8'
return response

Related

Download Html file instead of render in Django

So I am pretty much a django newbie, I do not even know if what I am asking is possible ;-;
So basically what I'm making is a website where users can pass context
Then django populates a template with the context
But instead of rendering the template I want to make the template populated with context available for download
I want to be able to download index.html
I know browsers have a save webpage feature but on mobile the javascript does not work and the icons i got from Google icons also do not load
This is pretty easy, your view ends with something like
return render(request,"index.html",context)
It should be changed to something like this
from io import StringIO
from django.http import FileReponse
response = render(request,"index.html",context)
f = io.StringIO(response.content)
return FileResponse(f, as_attachment = True, filename = "index.html")
It should be changed to something like this
from io import StringIO
from django.http import FileResponse
response = render(request,"index.html",context)
file = StringIO(response. Content)
return FileResponse(file, as_attachment = True, filename = "index.html")
Or if you are using such XML templates you can use it like this:
from io import BytesIO
from django.http import FileResponse
response = render(request,"index.html",context)
file = BytesIO(response. Content)
return FileResponse(file, as_attachment = True, filename = "index.xml")

Send a zip file as a response using python

I am given a zip file that I need to send to UI from where it should be downloaded for the user.
While testing on POSTMAN, using Send & Download button associated with POST, I am able to download the file. But when opening it, it says:
Windows cannot open the folder. The Compressed(zipped) folder <zip path> is invalid
Here's the code I am trying:
from django.response import Response
from rest_framework.views import APIView
def get_response():
with open(zip_file_path.zip, 'r', encoding='ISO-8859-1') as f:
file_data = f.read()
response = Response(file_data, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="ReportTest.zip"'
return response
class GenerateZIP(APIView):
def post(self, request):
zip_file_response = get_response()
return zip_file_response
The zip file read is valid as it's already on the local.
Any ideas?
Rather than generate the response yourself, you can use a FileResponse which does it for you
from django.http import FileResponse
from rest_framework.views import APIView
class GenerateZIP(APIView):
def post(self, request):
return FileResponse(
open('zip_file_path.zip', 'rb'),
as_attachment=True,
filename='ReportTest.zip'
)

User-specific download file in django

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

django current page to pdf

I am trying to create a "convert to pdf" button for a current page (service detail, which is a dynamic page) I tried to work with ReportLab (as Django documentation suggests, but I just can't make it work, and ReportLab documentation is not saying a word about such possibilities)
for now I can create a pdf file out of this view: (edit, got back to the code from django documentation for clarity)
views.py
#login_required
def service_detail(request, pk):
service = get_object_or_404(Service, pk=pk)
return render(request, 'detail.html', {'service':service, 'pk':pk})
#login_required
def render_to_pdf(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="service.pdf"''
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
p.drawString("Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
urls.py
url(r'^service/(?P<pk>\d+)/$', views.service_detail, name='service_detail'), #Services details
url(r'^render_to_pdf/', views.render_to_pdf, name='render_to_pdf'),
The template of the service detail includes dynamic elements, like:
Your location: {{ service.user_location }} <br><br>
Anyone knows what can I do, or what other technology I can use to create such PDF?
I am mostly working with Python, Django, HTML and CSS
content_type need to be application/pdf not service/pdf, also try to give pdf file name without spaces for example service.pdf, from docs, also you forgot to put attachment in Content-Disposition
try to write pdf to response like so and use BytesIO:
from io import BytesIO
#login_required
def render_to_pdf(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'inline; filename="service.pdf'
buffer = BytesIO()
p = canvas.Canvas(buffer)
# Start writing the PDF here
p.drawString(100, 100, 'Hello world.')
# End writing
p.showPage()
p.save()
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
You might want to consider the package django-wkhtmltopdf for generating PDF's in Django.
Using this, you can layout your PDF as an HTML-page (with CSS markup), like any other view, but it will render it as an PDF-file. Note that you will have to install the wkhtmltopdf binary to get it working.
By adding the ?as=html prefix in the url, you can view your page in the browser while developing.
The django-wkhtmltopdf package uses class based views. Here an example:
views.py
from django.utils.text import slugify
from wkhtmltopdf.views import PDFTemplateView
class Portfolio(PDFTemplateView):
template_name = 'frontend/portfolio.html'
def get_filename(self):
return slugify('portfolio ' + self.request.user.first_name + ' ' + self.request.user.last_name) + '.pdf'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
urls.py
from django.urls import path
from . import views
app_name = 'frontend'
urlpatterns = [
path(
'<slug:group_slug>/<int:school_year_pk>/portfolio/',
views.Portfolio.as_view(),
name='portfolio'
),
...

How to show a PDF file in a Django view?

Is it possible to show a PDF file in the Django view, rather than making the user have to download it to see it?
And if it is possible, how would it be done?
This is what I have so far -
#login_required
def resume(request, applicant_id):
#Get the applicant's resume
resume = File.objects.get(applicant=applicant_id)
fsock = open(resume.location, 'r')
response = HttpResponse(fsock, mimetype='application/pdf')
return response
Django has a class specifically for returning files, FileResponse. It streams files, so that you don't have to read the entire file into memory before returning it. Here you go:
from django.http import FileResponse, Http404
def pdf_view(request):
try:
return FileResponse(open('foobar.pdf', 'rb'), content_type='application/pdf')
except FileNotFoundError:
raise Http404()
If you have really large files or if you're doing this a lot, a better option would probably be to serve these files outside of Django using normal server configuration.
Simplistically, if you have a PDF file and you want to output it through a Django view, all you need to do is dump the file contents into the response and send it with the appropriate mimetype.
def pdf_view(request):
with open('/path/to/my/file.pdf', 'r') as pdf:
response = HttpResponse(pdf.read(), mimetype='application/pdf')
response['Content-Disposition'] = 'inline;filename=some_file.pdf'
return response
pdf.closed
You can probably just return the response directly without specifying Content-Disposition, but that better indicates your intention and also allows you specify the filename just in case the user decides to save it.
Also, note that the view above doesn't handle the scenario where the file cannot be opened or read for whatever reason. Since it's done with with, it won't raise any exceptions, but you still must return some sort of response. You could simply raise an Http404 or something, though.
PDF files must be opened as rb not r.
def pdf_view(request):
with open('/path / to /name.pdf', 'rb') as pdf:
response = HttpResponse(pdf.read(),content_type='application/pdf')
response['Content-Disposition'] = 'filename=some_file.pdf'
return response
Take out inline; if you want your file to be read from server. And also, the HttpResponse kwarg mimetype has been replaced by content_type:
(response['Content-Disposition'] = 'inline;filename=some_file.pdf')
def pdf_view(request):
with open('/app/../Test.pdf', 'r') as pdf:
response = HttpResponse(pdf.read(),content_type='application/pdf')
response['Content-Disposition'] = 'filename=some_file.pdf'
return response
pdf.closed
Following #radtek's answer above I decided to investigate a class-based view display. I tried to use View but it didn't have get_context_data() method.
I looked here for some guidance. I settled for BaseDetailView since I wanted to display just one object.
from django.http import FileResponse
from django.shortcuts import get_object_or_404
from django.views.generic.detail import BaseDetailView
class DisplayPdfView(BaseDetailView):
def get(self, request, *args, **kwargs):
objkey = self.kwargs.get('pk', None) #1
pdf = get_object_or_404(Pdf, pk=objkey) #2
fname = pdf.filename() #3
path = os.path.join(settings.MEDIA_ROOT, 'docs\\' + fname)#4
response = FileResponse(open(path, 'rb'), content_type="application/pdf")
response["Content-Disposition"] = "filename={}".format(fname)
return response
Commentary
1 This line accesses a named argument pk passed by the url calling the view.
2 This line gets the actual pdf model object.
3 I defined a method filename(self): return os.path.basename(self.file.name) in my model to help me get just the filename plus extension.
4 This line gets the complete filepath.
Then use file response as explained in the answers above. Also remember to use rb to read the pdf file
Here is a typical use-case for displaying a PDF using class-based views:
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
class DisplayPDFView(View):
def get_context_data(self, **kwargs): # Exec 1st
context = {}
# context logic here
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'inline; filename="worksheet_pdf.pdf"' # Can use attachment or inline
# pdf generation logic here
# open an existing pdf or generate one using i.e. reportlab
return response
# Remove login_required if view open to public
display_pdf_view = login_required(DisplayPDFView.as_view())
For generating your own pdf with reportlab see the Django project Docs on PDF Generation.
Chris Pratt's response shows a good example of opening existing PDFs.
Browsers aren't PDF readers (unless they have the proper plugin/addon).
You may want to render the PDF as HTML instead, which can be done from the backend or the frontend.
it worked for me
import re, os
import os
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def export_auto_doc(request):
name = request.GET.get('name', "")
filename = "path/to/file"+name+".pdf"
try:
if not re.search("^[a-zA-Z0-9]+$",name):
raise ValueError("Filename wrong format")
elif not os.path.isfile(filename):
raise ValueError("Filename doesn't exist")
else:
with open(filename, 'r') as pdf:
response = HttpResponse(pdf.read(), content_type='application/pdf')
response['Content-Disposition'] = 'inline;filename='+name+'.pdf'
return response
pdf.closed
except ValueError as e:
HttpResponse(e.message)
The easiest way to do this is probably with an anchor in a template. For example, if you are using Django's templating engine (as most people who search for this probably are), simply serve it as a static file through an anchor.
In your template that will contain a link to the file, add at the very top
{% load static %}
Then, wherever you want to link to your pdf, put
Click me
The first line tells Django to look in the directories configured for static files in settings.py. The path that you use in the anchor tag is relative to any of the directories that you configured as static directories in settings.py. When you click the rendered link, it should display the PDF in your browser, provided you have your static files pathed correctly.
I am just throwing this out there.
You can simply add your PDF resume to your static files.
If you are using White Noise to serve your static files, then you don't even need to make the view. Just then access your resume at the static location.
I added mine, here it is: TIm-D_Nice.pdf
Warning: This doesn't solve the login_required requirement in the question
Use iframe url=url of pdf tag and give url of that pdf and make sure that your user will have full control of the project then pdf will be displayed on web screen
def pdf_view(request,pdfSlug):
a = Pdf.objects.get(pdf_slug=pdfSlug)
with open(str(a.pdf_file.path), 'rb') as pdf:
response = FileResponse(pdf.read(), content_type='application/pdf')
response['Content-Disposition'] = 'filename=a.pdf'
return response
pdf.closed
look this i'ts warked for me

Categories

Resources