Create Download PDF File and store it into a Model - python

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)

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!

How to send file to response in Django?

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

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)

How to upload multiple images using FaceBook Python SDK?

I have three images image1.jpg ,image2.jpg, image3.jpg. I am trying to upload them as a single post. Below is my code:
import facebook
graph = facebook.GraphAPI(oauth_access_token)
profile = graph.get_object("me")
friends = graph.get_connections("me", "friends")
file1 = open("image1","rb")
file2 = open('image2', 'rb')
graph.put_photo(file1, 'Look at this cool photo!')
graph.put_photo(file2, 'Look at this cool photo!')
But they get uploaded as separate posts in separate images. How do I upload multiple images in single post?
If someone looking to post Multiple Images or a Video in 2021 using Graph API in Python
import requests
auth_token = "XXXXXXXX"
def postImage(group_id, img):
url = f"https://graph.facebook.com/{group_id}/photos?access_token=" + auth_token
files = {
'file': open(img, 'rb'),
}
data = {
"published" : False
}
r = requests.post(url, files=files, data=data).json()
return r
def multiPostImage(group_id):
imgs_id = []
img_list = [img_path_1, img_path_2]
for img in img_list:
post_id = postImage(group_id ,img)
imgs_id.append(post_id['id'])
args=dict()
args["message"]="Put your message here"
for img_id in imgs_id:
key="attached_media["+str(imgs_id.index(img_id))+"]"
args[key]="{'media_fbid': '"+img_id+"'}"
url = f"https://graph.facebook.com/{group_id}/feed?access_token=" + auth_token
requests.post(url, data=args)
multiPostImage("426563960691001")
same way it work for page, use page_id instead of group_id
Posting a Video
def postVideo(group_id, video_path):
url = f"https://graph-video.facebook.com/{group_id}/videos?access_token=" + auth_token
files = {
'file': open(video_path, 'rb'),
}
requests.post(url, files=files)
First, you have to upload all photos and keep the id's (imgs_id).
Then, make a dict like args, and finally call request method.
imgs_id = []
for img in img_list:
photo = open(img, "rb")
imgs_id.append(api.put_photo(photo, album_id='me/photos',published=False)['id'])
photo.close()
args=dict()
args["message"]="Put your message here"
for img_id in imgs_id:
key="attached_media["+str(imgs_id.index(img_id))+"]"
args[key]="{'media_fbid': '"+img_id+"'}"
api.request(path='/me/feed', args=None, post_args=args, method='POST')
have you tried: put-wall-post ? ..or put-object
put-wall-post might be what you are looking for:
attachment - A dict that adds a structured attachment to the message being posted to the Wall. If you are sharing a URL, you will want to use the attachment parameter so that a thumbnail preview appears in the post. It should be a dict of the form:
Source: http://facebook-sdk.readthedocs.io/en/latest/api.html#api-reference

Categories

Resources