How to send file to response in Django? - python

I have such php function which I try to rewrite in my Django project. What should be an analogue in python for php methods like header() and show_error()? Also how to send file to response?
php:
function waprfile($date=false) {
if(!isset($date) || $date==false) $date = date("d.m.y");
$timestmp = date2timestamp($date);
$filepath = "https://www.example.com/files/".$this->lang_code."/";
if(file_get_contents($filepath.date("dmy",$timestmp).".xls"))
{
header("Location: ".$filepath."wapr".date("dmy",$timestmp).".xls");
}
else
{
show_error(_langWrite("No file for specified date", "Файл на указанную дату отсутствует"));
}
}
python:
import urllib.request
import datatime
import time
from django.utils import translation
def isset(variable):
return variable in locals() or variable in globals()
def waprfile(request, date):
if(not isset(date) or date==False):
date = datetime.datetime.now().strftime('%d.%m.%Y')
timestmp = time.mktime(datatime.datetime.strptime(date, "%d.%m.%Y").timetuple())
filepath = "https://www.example.com/files/" + str(translation.get_language()) + "/"
formatted_date = datetime.datetime.fromtimestamp(timestmp).strftime('%d%m%y')
if(urllib.request.urlopen(filepath + formatted_date + '.xls')):
# What must be here?
else:
# What must be here?
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename=' + fileName
return response

Read file first and then send it in response.
from django.http import HttpResponse, HttpResponseNotFound
def waprfile(request, date):
...
file_location = '/path/to/file/foo.xls'
try:
with open(file_location, 'r') as f:
file_data = f.read()
# sending response
response = HttpResponse(file_data, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'
except IOError:
# handle file not exist case here
response = HttpResponseNotFound('<h1>File not exist</h1>')
return response
Read docs for more info:
telling browser to treat the response as a file attachment and returning errors

To return a PDF file in response in Django, use below code.
def index(request):
data = dict()
data["name"] = "https://www.pythoncircle.Com"
data["DOB"] = "Jan 10, 2015"
template = get_template('testapp/test.html')
html = template.render(data)
pdf = pdfkit.from_string(html, False)
filename = "sample_pdf.pdf"
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="' + filename + '"'
return response
[1] https://www.pythoncircle.com/post/470/generating-and-returning-pdf-as-response-in-django/

If you want to return an image don't forget to format it as png or jpeg and return the bytes with getvalue()
img = "Suppose I am a pil image"
fomatted_img = BytesIO()
img.save(fomatted_img, format="png")
response = HttpResponse(fomatted_img.getvalue(),content_type='image/png')
response['Content-Disposition'] = 'attachment; filename="output.png"'
return response
Or you can save the formatted image directly into the response
img = "Suppose I am a pil image"
response = HttpResponse(content_type='image/png')
response['Content-Disposition'] = 'attachment; filename="output.png"'
img.save(response,"PNG")
return response

Related

Extract specifit pages and make new pdf from list of pdfs

I have been trying to get spacfic pages extract from each pdf and then merge all the extracted pdf in once.
I have list of pdfs
I am using pdfrw this library but getting error while extracting the pages
from pdfrw import PdfReader, PdfWriter
import os
files = [f for f in os.listdir(
'.') if os.path.isfile(f) and f.endswith('.pdf')]
print(files)
for pdf in files:
pages = PdfReader(pdf).pages
parts = [(6, 7)]
for part in parts:
title = pdf.title().split('.')[0]
outdata = PdfWriter(f'{title}_{part[0]}_.pdf')
for pagenum in range(*part):
outdata.addpage(pages[pagenum-1])
outdata.write()
Please help if possible
raise PdfParseError('Invalid PDF header: %s' %
pdfrw.errors.PdfParseError: Invalid PDF header: '<!doctype html>'
Manas,
One way to achieve your requirement is to use API. For example, consider following code snippet where it splits PDF from uploaded file.
import os
import requests # pip install requests
# The authentication key (API Key).
# Get your own by registering at https://app.pdf.co
API_KEY = "*********************************"
# Base URL for PDF.co Web API requests
BASE_URL = "https://api.pdf.co/v1"
# Source PDF file
SourceFile = ".\\sample.pdf"
# Comma-separated list of page numbers (or ranges) to process. Example: '1,3-5,7-'.
Pages = "1-2,3-"
def main(args = None):
uploadedFileUrl = uploadFile(SourceFile)
if (uploadedFileUrl != None):
splitPDF(uploadedFileUrl)
def splitPDF(uploadedFileUrl):
"""Split PDF using PDF.co Web API"""
# Prepare requests params as JSON
# See documentation: https://apidocs.pdf.co
parameters = {}
parameters["pages"] = Pages
parameters["url"] = uploadedFileUrl
# Prepare URL for 'Split PDF' API request
url = "{}/pdf/split".format(BASE_URL)
# Execute request and get response as JSON
response = requests.post(url, data=parameters, headers={ "x-api-key": API_KEY })
if (response.status_code == 200):
json = response.json()
if json["error"] == False:
# Download generated PNG files
part = 1
for resultFileUrl in json["urls"]:
# Download Result File
r = requests.get(resultFileUrl, stream=True)
localFileUrl = f"Page{part}.pdf"
if r.status_code == 200:
with open(localFileUrl, 'wb') as file:
for chunk in r:
file.write(chunk)
print(f"Result file saved as \"{localFileUrl}\" file.")
else:
print(f"Request error: {response.status_code} {response.reason}")
part = part + 1
else:
# Show service reported error
print(json["message"])
else:
print(f"Request error: {response.status_code} {response.reason}")
def uploadFile(fileName):
"""Uploads file to the cloud"""
# 1. RETRIEVE PRESIGNED URL TO UPLOAD FILE.
# Prepare URL for 'Get Presigned URL' API request
url = "{}/file/upload/get-presigned-url?contenttype=application/octet-stream&name={}".format(
BASE_URL, os.path.basename(fileName))
# Execute request and get response as JSON
response = requests.get(url, headers={ "x-api-key": API_KEY })
if (response.status_code == 200):
json = response.json()
if json["error"] == False:
# URL to use for file upload
uploadUrl = json["presignedUrl"]
# URL for future reference
uploadedFileUrl = json["url"]
# 2. UPLOAD FILE TO CLOUD.
with open(fileName, 'rb') as file:
requests.put(uploadUrl, data=file, headers={ "x-api-key": API_KEY, "content-type": "application/octet-stream" })
return uploadedFileUrl
else:
# Show service reported error
print(json["message"])
else:
print(f"Request error: {response.status_code} {response.reason}")
return None
if __name__ == '__main__':
main()
Now, to merge PDF file you can use similar to following code snippet.
import os
import requests # pip install requests
# The authentication key (API Key).
# Get your own by registering at https://app.pdf.co
API_KEY = "**********************************"
# Base URL for PDF.co Web API requests
BASE_URL = "https://api.pdf.co/v1"
# Source PDF files
SourceFile_1 = ".\\sample1.pdf"
SourceFile_2 = ".\\sample2.pdf"
# Destination PDF file name
DestinationFile = ".\\result.pdf"
def main(args = None):
UploadedFileUrl_1 = uploadFile(SourceFile_1)
UploadedFileUrl_2 = uploadFile(SourceFile_2)
if (UploadedFileUrl_1 != None and UploadedFileUrl_2!= None):
uploadedFileUrls = "{},{}".format(UploadedFileUrl_1, UploadedFileUrl_2)
mergeFiles(uploadedFileUrls, DestinationFile)
def mergeFiles(uploadedFileUrls, destinationFile):
"""Perform Merge using PDF.co Web API"""
# Prepare requests params as JSON
# See documentation: https://apidocs.pdf.co
parameters = {}
parameters["name"] = os.path.basename(destinationFile)
parameters["url"] = uploadedFileUrls
# Prepare URL for 'Merge PDF' API request
url = "{}/pdf/merge".format(BASE_URL)
# Execute request and get response as JSON
response = requests.post(url, data=parameters, headers={ "x-api-key": API_KEY })
if (response.status_code == 200):
json = response.json()
if json["error"] == False:
# Get URL of result file
resultFileUrl = json["url"]
# Download result file
r = requests.get(resultFileUrl, stream=True)
if (r.status_code == 200):
with open(destinationFile, 'wb') as file:
for chunk in r:
file.write(chunk)
print(f"Result file saved as \"{destinationFile}\" file.")
else:
print(f"Request error: {response.status_code} {response.reason}")
else:
# Show service reported error
print(json["message"])
else:
print(f"Request error: {response.status_code} {response.reason}")
def uploadFile(fileName):
"""Uploads file to the cloud"""
# 1. RETRIEVE PRESIGNED URL TO UPLOAD FILE.
# Prepare URL for 'Get Presigned URL' API request
url = "{}/file/upload/get-presigned-url?contenttype=application/octet-stream&name={}".format(
BASE_URL, os.path.basename(fileName))
# Execute request and get response as JSON
response = requests.get(url, headers={ "x-api-key": API_KEY })
if (response.status_code == 200):
json = response.json()
if json["error"] == False:
# URL to use for file upload
uploadUrl = json["presignedUrl"]
# URL for future reference
uploadedFileUrl = json["url"]
# 2. UPLOAD FILE TO CLOUD.
with open(fileName, 'rb') as file:
requests.put(uploadUrl, data=file, headers={ "x-api-key": API_KEY, "content-type": "application/octet-stream" })
return uploadedFileUrl
else:
# Show service reported error
print(json["message"])
else:
print(f"Request error: {response.status_code} {response.reason}")
return None
if __name__ == '__main__':
main()
In this sample I am using pdf.co API. Refer to following links for more information.
https://apidocs.pdf.co/30-pdf-split, https://apidocs.pdf.co/31-pdf-merge
Thanks!

using urllib3 module instead of requests in python

This code works correctly in python 2.X version. I am trying to use the similar code in python version 3.
The problem is that I do not want to use requests module. I need to make it work using "urllib3".
import requests
import urllib
event = {'url':'http://google.com', 'email':'abc#gmail.com', 'title':'test'}
url = event['url']
if event['email']:
email=event['email']
if event['title']:
title=event['title']
url1 = urllib.parse.unquote(url)
myfile=urllib.request.urlopen(url1)
requests.post("https://api.mailgun.net/v3/xxx.mailgun.org/messages",
auth=("api", "key-xxx"),
files=[("attachment", myfile)
],
data={"from": "Excited User <excited-user#example.com>",
"to": email,
"subject": title,
"text": "Testing some awesomness with attachments!",
"html": myfile})
I am getting TypeError while trying to run this code:
import urllib3
event = {'url':'http://oksoft.blogspot.com', 'email':'abc#gmail.com', 'title':'test'}
url = event['url']
if event['email']:
email=event['email']
if event['title']:
title=event['title']
url1 = urllib.parse.unquote(url)
myfile=urllib.request.urlopen(url1)
http = urllib3.PoolManager()
url = "https://api.mailgun.net/v3/xxx.mailgun.org/messages"
params={"from": "Excited User <excited-user#example.com>",
"to": email,
"subject": title,
"text": "Testing some awesomness with attachments!",
"html": myfile}
http.request(
"POST", url, headers={"Content-Type": "application/json", "api":"key-xxx"}, body= params
)
This code uses the urllib.reqeust module. To actually create a file attachment as opposed to inline html content is a bit more involved than setting an html parameter with file contents.
import urllib.request
import urllib.error
import urllib.parse
import io
import mimetypes
import uuid
class MultiPartForm:
"""Accumulate the data to be used when posting a form."""
def __init__(self):
self.form_fields = []
self.files = []
# Use a large random byte string to separate
# parts of the MIME data.
self.boundary = uuid.uuid4().hex.encode('utf-8')
return
def get_content_type(self):
return 'multipart/form-data; boundary={}'.format(
self.boundary.decode('utf-8'))
def add_field(self, name, value):
"""Add a simple field to the form data."""
self.form_fields.append((name, value))
def add_file(self, fieldname, filename, fileHandle,
mimetype=None):
"""Add a file to be uploaded."""
body = fileHandle.read()
if mimetype is None:
mimetype = (
mimetypes.guess_type(filename)[0] or
'application/octet-stream'
)
self.files.append((fieldname, filename, mimetype, body))
return
#staticmethod
def _form_data(name):
return ('Content-Disposition: form-data; '
'name="{}"\r\n').format(name).encode('utf-8')
#staticmethod
def _attached_file(name, filename):
return ('Content-Disposition: file; '
'name="{}"; filename="{}"\r\n').format(
name, filename).encode('utf-8')
#staticmethod
def _content_type(ct):
return 'Content-Type: {}\r\n'.format(ct).encode('utf-8')
def __bytes__(self):
"""Return a byte-string representing the form data,
including attached files.
"""
buffer = io.BytesIO()
boundary = b'--' + self.boundary + b'\r\n'
# Add the form fields
for name, value in self.form_fields:
buffer.write(boundary)
buffer.write(self._form_data(name))
buffer.write(b'\r\n')
buffer.write(value.encode('utf-8'))
buffer.write(b'\r\n')
# Add the files to upload
for f_name, filename, f_content_type, body in self.files:
buffer.write(boundary)
buffer.write(self._attached_file(f_name, filename))
buffer.write(self._content_type(f_content_type))
buffer.write(b'\r\n')
buffer.write(body)
buffer.write(b'\r\n')
buffer.write(b'--' + self.boundary + b'--\r\n')
return buffer.getvalue()
event = {'url':'http://oksoft.blogspot.com', 'email':'abc#gmail.com', 'title':'test'}
url = event['url']
if event['email']:
email=event['email']
if event['title']:
title=event['title']
form = MultiPartForm()
form.add_field("from", "Excited User <excited-user#example.com>")
form.add_field("to", email)
form.add_field("subject", title)
form.add_field("text", "Testing some awesomness with attachments!")
with urllib.request.urlopen(url) as f:
form.add_file("attachment", "test.html", f, "text/html")
url = "https://api.mailgun.net/v3/xxx.mailgun.org/messages"
# create basic authorization opener
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='MG API',
uri=url,
user='api',
passwd='xxx-key')
opener = urllib.request.build_opener(auth_handler)
data = bytes(form)
req = urllib.request.Request(url, data=data)
req.add_header('Content-type', form.get_content_type())
req.add_header('Content-length', len(data))
with opener.open(req) as f:
print(f.read().decode('utf-8'))
It returns a TypeError: can't concat str to bytes because your myfile is of type http.client.HTTPResponse, not of type str -- which needs to be passed to the request body.
So gotta first transform the response to a string and then json-serialize the body params.
Full code:
import urllib3
import urllib.request
import urllib.parse
import json
event = {'url': 'http://oksoft.blogspot.com',
'email': 'abc#gmail.com', 'title': 'test'}
url = event['url']
if event['email']:
email = event['email']
if event['title']:
title = event['title']
url1 = urllib.parse.unquote(url)
myfile = urllib.request.urlopen(url1)
myfile_content = myfile.read()\
.decode(myfile.headers
.get_content_charset(failobj='utf-8'))
http = urllib3.PoolManager()
url = "https://api.mailgun.net/v3/xxx.mailgun.org/messages"
params = {"from": "Excited User <excited-user#example.com>",
"to": email,
"subject": title,
"text": "Testing some awesomness with attachments!",
"html": myfile_content}
### EDIT
auth_headers = urllib3.util.make_headers(
basic_auth='api:xxx')
r = http.request(
"POST",
url,
headers=auth_headers,
fields=params
)
print(r.status, r.data)

Create Download PDF File and store it into a Model

I've created a PDF Creator with WeasyPrint and included the download function. Is it now possible to store that PDF File immediately into a Model-FileField (called Invoice)? How should this code look like?
def generate_pdf(request):
# Rendered
html_string = render_to_string('bills/pdf/invoice.html', context)
html = HTML(string=html_string, base_url=request.build_absolute_uri())
result = html.write_pdf(stylesheets=[CSS(settings.STATIC_ROOT + '/css/bills.css')], presentational_hints=True);
# Creating http response
response = HttpResponse(content_type='application/pdf;')
invoice_number = context['invoice_id']
filename = "Invoice" + str(invoice_number) + ".pdf"
response['Content-Disposition'] = 'inline; filename="{}"'.format(filename)
pdf_file = HTML(string=html_string,
base_url=settings.MEDIA_ROOT).write_pdf()
new_bill = Invoice(invoice_no=billNumber, invoice_file=temp)
new_bill.save()
response['Content-Transfer-Encoding'] = 'binary'
with tempfile.NamedTemporaryFile(delete=True) as output:
output.write(result)
output.flush()
output = open(output.name, 'rb')
response.write(output.read())
download = request.GET.get("download")
if download:
content = "attachment; filename='%s'" %(filename)
response['Content-Disposition'] = output
return response
Here is a complete example from Django documentation, to access instance information in your models to build path with user id :
models.py
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class YourClass(models.Model):
invoice = models.FileField(default='default.pdf', upload_to=user_directory_path)

Insert number as folderID

I'm getting a new little problem with API Rest Python between Django and LogicalDOC.
I'm creating a folder inside LogicalDOC, then I would like to save my pdf file inside this new folder taking the folderId.
But, when it seems work because the syntax is good from my point of view : none pdf file appears.
I create a folder, I pick up his ID number : 348930 for example with the command data["id"] and I insert str(data["id"]) in FolderId when I want to save my pdf file in the new folder.
The new folder is created and worked well, but the pdf file is not save inside. Something wrong ?
This is my script :
#login_required
def BirthCertificate_PDF(request, id) :
birthcertificate = get_object_or_404(BirthCertificate, pk=id)
data = {"birthcertificate" : birthcertificate}
template = get_template('BC_raw.html')
html = template.render(Context(data))
filename_directory = str(BirthCertificate.objects.get(pk=id).lastname.encode('utf-8')) + "_" + str(BirthCertificate.objects.get(pk=id).firstname.encode('utf-8')) + "_" + str(BirthCertificate.objects.get(pk=id).birthday)
filename = 'Acte_Naissance_' + filename_directory + '.pdf'
path = '/Users/valentinjungbluth/Desktop/Django/Individus/' + filename
file = open(path, "w+b")
pisaStatus = pisa.CreatePDF(html.encode('utf-8'), dest=file, encoding='utf-8')
file.seek(0)
pdf = file.read()
if pdf :
payload = '{{ "name":"{0}", "parentId":3309569 }}'.format(filename_directory) #Fix parent folder
url = 'http://localhost:8080/services/rest/folder/create'
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
resp = requests.post(url, data=payload, headers=headers, auth=('admin', 'admin'))
rbody = resp.content
data = json.loads(rbody)
print data["id"] #Get ID from the new folder
payload = '{{ "language":"fr","fileName":"{0}","FolderId":'+str(data["id"]) +'}}'.format(filename) #save pdf file inside the new folder thanks to his ID
upfile = path
files = {
'document': (None, payload, 'application/json'),
'content': (os.path.basename(upfile), open(upfile, 'rb'), 'application/octet-stream')
}
url = 'http://localhost:8080/services/rest/document/create'
headers = {'Content-Type': 'multipart/form-data'}
r = requests.post(url, files=files, headers=headers, auth=('admin', 'admin'))
context = {"birthcertificate":birthcertificate,
"path":path}
return render(request, 'BC_PDF.html', context)
file.close()
return HttpResponse(pdf, 'application/pdf')
This is a screen capture which shows that folderID should be : 3538970
This number is also given by : data["id"]
As I said in my comment you don't need to use string concatenation to pass FolderId as payload, just use second argument of format method:
d = '{{ "language":"fr","fileName":"{0}","FolderId":"{1}"}}'.format(‌​filename, str(data["id"]))

Include path in filename when creating a pdf

I have a script which let to generate a PDF file and then send it to another application (LogicalDOC) in order to save it.
I'm getting a problem with payload line. The filename should be my filename variable but it doesn't take account.
If I write filename.pdf, I find filename.pdf in LogicalDOC with the good content.
But filename have to change automatically for each new BirthCertificate.
How I can pass the path as filename ?
This is my script :
#login_required
def BirthCertificate_PDF(request, id) :
birthcertificate = get_object_or_404(BirthCertificate, pk=id)
data = {"birthcertificate" : birthcertificate}
template = get_template('BC_raw.html')
html = template.render(Context(data))
filename_directory = str(BirthCertificate.objects.get(pk=id).lastname.encode('utf-8')) + "_" + str(BirthCertificate.objects.get(pk=id).firstname.encode('utf-8')) + "_" + str(BirthCertificate.objects.get(pk=id).birthday)
filename = 'Acte_Naissance_' + filename_directory + '.pdf'
path = '/Users/valentinjungbluth/Desktop/Django/Individus/' + filename
file = open(path, "w+b")
pisaStatus = pisa.CreatePDF(html.encode('utf-8'), dest=file, encoding='utf-8')
file.seek(0)
pdf = file.read()
if pdf :
payload = '{ "language":"fr","fileName":filename,"folderId":3309569 }'
upfile = path
files = {
'document': (None, payload, 'application/json'),
'content': (os.path.basename(upfile), open(upfile, 'rb'), 'application/octet-stream')
}
url = 'http://localhost:8080/services/rest/document/create'
headers = {'Content-Type': 'multipart/form-data'}
r = requests.post(url, files=files, headers=headers, auth=('admin', 'admin'))
context = {"birthcertificate":birthcertificate,
"path":path}
return render(request, 'BC_PDF.html', context)
file.close()
return HttpResponse(pdf, 'application/pdf')
If I wrote :
"FileName":"test.pdf" I obtain the test.pdf file in logicalDoc (see picture)
"FileName":"filename" I obtain the filename file with unknown format in logicalDoc (see picture)
I would like to get my filename variable as document name
You can use string formatting for this. Just do follow:
payload = '{{ "language":"fr","fileName":"{0}","folderId":3309569 }}'.format(filename)

Categories

Resources