I'm trying to create a PDF with checkboxes that can be checked (using python). I've been trying to use pisa to generate the pdf and have looked around the internet and tried different examples but I cannot find out how to make an editable PDF.
This is my most recent attempt:
import cStringIO
import ho.pisa as pisa
import os
# shortcut for dumping all logs on screen
pisa.showLogging()
def HTML2PDF(data, filename, open=False):
"""
Simple test showing how to create a PDF file from
PML Source String. Also shows errors and tries to start
the resulting PDF
"""
pdf = pisa.CreatePDF(cStringIO.StringIO(data), file(filename, "wb"))
if open and not(pdf.err):
os.startfile(str(filename))
return not pdf.err
if __name__=="__main__":
HTMLTEST = """
<html>
<body>
<form name="deleteForm" method="get" action="">
User 1 <input type="checkbox" name="user" value="delete" />
</form>
</body>
</html>
"""
HTML2PDF(HTMLTEST, "test.pdf", open=True)
The form gives me an error:
Traceback (most recent call last):
File "C:/Users/horeth/PycharmProjects/Reportlab/HTMLtoPF/Main.py", line 32, in
HTML2PDF(HTMLTEST, "test.pdf", open=True)
File "C:/Users/horeth/PycharmProjects/Reportlab/HTMLtoPF/Main.py", line 14, in HTML2PDF
pdf = pisa.CreatePDF(cStringIO.StringIO(data), file(filename, "wb"))
IOError: [Errno 13] Permission denied: 'test.pdf'
The check boxes are for readers to decide if a user needs to be deleted or not.
I'm wondering if there is a way to create an editable PDF document with Python. This is just one of the attempts I've made so far, as an example.
Possible reasons. You don't have write permission to the directory. The file already exists but you do not have write access to it.
import cStringIO as StringIO
from xhtml2pdf import pisa
from django.template.loader import get_template
from django.template import Context
from cgi import escape
def render_to_pdf(template_path, context_dict):
template = get_template(template_path)
html = template.render(context_dict)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-
1")), dest=result)
if not pdf.err:
return HttpResponse(result.getvalue(),
content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' %
escape(html))
Call this function
def myview(request):
return render_to_pdf('HTMLTEST.html', { 'pagesize':'A4',})
create a seperate html file
HTMLTEST.html
<html>
<body>
<form name="deleteForm" method="get" action="">
User 1 <input type="checkbox" name="user" value="delete" />
</form>
</body>
</html>
Related
My objective is to read the contents of a worksheet uploaded by the user and apply a function to it. So far the uploading works perfect and i see the file in the server.
However every time i try to select the file from the list i keep getting this error:
Invalid file path or buffer object type: <class 'django.db.models.query.QuerySet'>
Right here is the view that handles the file selection the the template and returns an excel file where the data was processed to be downloaded (for example if i want to filter out all duplicates and return clean data so i upload the excel sheet and return the filtered excel file.):
# get file run func on it and return new excel file, view needs to handle url
def dataprocess(self, pk):
data = Worksheet.objects.filter(pk=pk)
df = pd.read_excel(data, engine='xlrd')
#finishdata = dataprocessor(df) // ignore this part for now.
print("HERE---------------------->", df.url)
# return excel file
response = HttpResponse(content_type='application/vnd.ms-excel')
# tell the browser what the file is named
response['Content-Disposition'] = 'attachment;filename="ezpassreport.xlsx"'
# put the spreadsheet data into the response
response.write(df.getvalue())
return response
This is the HTML Page:
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Select Report
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
{% for i in worksheet %}
{{i.worksheet}}<br>
{% endfor %}
</div>
And the urls just in case:
from ezpass.views import ezpass, file_upload, dataprocess
from django.urls import path
app_name = 'ezpass'
urlpatterns = [
path('ezpass/', ezpass, name="ezpass"),
path('upload/', file_upload, name='upload'),
path('dataprocess/<int:pk>', dataprocess, name='dataprocess')
]
This is how i fixed it.
#handles the download and data processing of the ezpass data
def dataprocess(self, pk):
data = Worksheet.objects.get(pk=pk)
path = data.worksheet.path
df = pd.read_excel(os.path.join(BASE_DIR, path), engine='openpyxl')
finishdata: pd = dataprocessor(df)
# return excel file
response = HttpResponse(content_type='application/vnd.ms-excel')
# tell the browser what the file is named
response['Content-Disposition'] = 'attachment;filename="ezpassreport.xlsx"'
# put the spreadsheet data into the response
response.write(finishdata)
return response
I've checked on stackoverflow and other places and everywhere they use files.filename to check if a file is available or not. If I do this I get the message
AttributeError: 'list' object has no attribute 'filename'
Do I miss something? Or is there another way to check if the user has selected a file to upload?
my HTML:
<form method="POST" enctype="multipart/form-data" action="/upload">
<label>Choose a problem report file (*.zip).
<input type="file" name="file[]" multiple="" accept=".zip">
<input type="submit" value="Upload problem report(s)">
</label>
</form>
my python
import flask
from werkzeug.wrappers import request
import os
app = flask.Flask("upload")
UPLOAD_FOLDER = './upload'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def get_html(page_name):
html_file = open(page_name + ".html")
content = html_file.read()
html_file.close()
return content
#app.route("/upload", methods=["POST"])
def upload():
files = flask.request.files.getlist("file[]")
if files.filename !='':
for file in files:
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
return get_html("index")
It's not the best code I know, but if I leave out the check for the filename the upload works.
It should be something like this:
files = flask.request.files.getlist("file[]")
for file in files:
if file.filename !='':
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
As the error message suggested, your get a list, and a list has not filename attribute, so you need to check the items in the list.
So I have come HTML code that lets the user input an image:
<label class="tab-item"> Browse
<span class="icon icon-more"></span>
<input type="file" accept="image/*" name="image_save" value="image_save" onchange="updatePhoto(event);"></input>
</label>
#some more code
<form action="../api/save" method="post">
<button type="submit" name="image_save" class="btn btn-positive btn-block" href="../api.put" value="image_save">
Test Save
</button>
</form>
And in a Python file I have:
#cherrypy.expose
def save(self, image_save=None):
f = open(image_save)
f.save("../photos/" + "test" + ".png", "PNG")
return "Image saved"
However I get the error
IOError: [Errno 2] No such file or directory: u'image_save'"
How would you guys save the image that is given through the HTML code? What type of data is being given as the method argument?
There is a mimimal example at this site which gives this example for a python file upload:
#!/usr/local/bin/python
"""This demonstrates a minimal http upload cgi.
This allows a user to upload up to three files at once.
It is trivial to change the number of files uploaded.
This script has security risks. A user could attempt to fill
a disk partition with endless uploads.
If you have a system open to the public you would obviously want
to limit the size and number of files written to the disk.
"""
import cgi
import cgitb; cgitb.enable()
import os, sys
try: # Windows needs stdio set for binary mode.
import msvcrt
msvcrt.setmode (0, os.O_BINARY) # stdin = 0
msvcrt.setmode (1, os.O_BINARY) # stdout = 1
except ImportError:
pass
UPLOAD_DIR = "/tmp"
HTML_TEMPLATE = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>File Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head><body><h1>File Upload</h1>
<form action="%(SCRIPT_NAME)s" method="POST" enctype="multipart/form-data">
File name: <input name="file_1" type="file"><br>
File name: <input name="file_2" type="file"><br>
File name: <input name="file_3" type="file"><br>
<input name="submit" type="submit">
</form>
</body>
</html>"""
def print_html_form ():
"""This prints out the html form. Note that the action is set to
the name of the script which makes this is a self-posting form.
In other words, this cgi both displays a form and processes it.
"""
print "content-type: text/html\n"
print HTML_TEMPLATE % {'SCRIPT_NAME':os.environ['SCRIPT_NAME']}
def save_uploaded_file (form_field, upload_dir):
"""This saves a file uploaded by an HTML form.
The form_field is the name of the file input field from the form.
For example, the following form_field would be "file_1":
<input name="file_1" type="file">
The upload_dir is the directory where the file will be written.
If no file was uploaded or if the field does not exist then
this does nothing.
"""
form = cgi.FieldStorage()
if not form.has_key(form_field): return
fileitem = form[form_field]
if not fileitem.file: return
fout = file (os.path.join(upload_dir, fileitem.filename), 'wb')
while 1:
chunk = fileitem.file.read(100000)
if not chunk: break
fout.write (chunk)
fout.close()
save_uploaded_file ("file_1", UPLOAD_DIR)
save_uploaded_file ("file_2", UPLOAD_DIR)
save_uploaded_file ("file_3", UPLOAD_DIR)
print_html_form ()
Additional Suggestions
I would suggest you change the input type to
<input type="file" name="image_save" accept="image/x-png,image/gif,image/jpeg" />
instead of image/* to limit to png/jpg/gif. MIME type can be checked using php and i would also suggest you add a upload_max_filesize (in php also)
Finally change the fout line to
fout = open(pathname, 'wb')
While the file() constructor is an alias for open(), for future and backwards compatibility, open() remains preferred.
I'm trying to work file upload example in this website https://www.tutorialspoint.com/python/python_cgi_programming.htm
I have written a .py file. When i run this code, following error is occurs;
Traceback (most recent call last):
File "C:/xampp/cgi-bin/file_upload.py", line 9, in <module>
fileitem = form['filename']
File "C:\Python3\lib\cgi.py", line 604, in __getitem__
raise KeyError(key)
KeyError: 'filename'
And my .py file is below:
#!C:/Python3/python.exe
import cgi, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
# Get filename here.
fileitem = form['filename']
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid
# directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('F:/gelen/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print ("""\
Content-Type: text/html\n
<html>
<body>
<form enctype="multipart/form-data"
action="/cgi-bin/file_upload.py" method="post">
<p>File: <input type="file" name="filename" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
<p>%s</p>
</body>
</html>
""" % (message,))
How Can i solve this problem and why program doesn't see filename i don't understand
If the directory where the script is running is /path/to/dir then the /path/to/dir/files directory must exist. If it does not it will fail.
and also to upload a file the HTML form must have the enctype attribute set to multipart/form-data.
Perhaps it is late for the person who asked, but I came across a similar problem. The following is what worked for me. As your error message shows the problem is coming from the line. fileitem = form['filename'] We can run the file in the browser as http://localhost:xxxx/file_upload.py What you'll see is the 'browse' button and the 'upload' button. Unless you browse and load some file the 'form' object won't be populated. It wouldn't contain the key 'filename', yet. We get the keyerror. So we need to put it inside an if statement. I also found some formatting error with the html part of the code. I slightly edited the code which is pasted below, runs well on Linux.
#!/usr/bin/python3
import cgi, sys, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
print('Content-type: text/html')
sys.path.insert(0, os.getcwd())
message = None
# Test if the file is loaded for the upload
if 'filename' in form:
fileitem = form['filename']
fn = os.path.basename(fileitem.filename)
open('/home/jk/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
replyhtml = """
<html>
<body>
<form enctype="multipart/form-data" action="/cgi-bin/file_upload.py" method="post">
<p>File: <input type="file" name="filename" /></p>
<p><input type="submit" value="Upload" name=action/></p>
</form>
<p>%s</p>
</body>
</html>
"""
print(replyhtml % message)
I believe you have your server running in the current working directory. And the .py file need to be in the cgi-bin folder. A simple http server script:
import os
from http.server import HTTPServer, CGIHTTPRequestHandler
servaddr = ("localhost", 8888)
#http.server.SimpleHTTPRequestHandler(request, client_address, server)
server = HTTPServer(servaddr, CGIHTTPRequestHandler)
server.serve_forever()
References:
Programming Python, Mark Lutz, 4th edition, Chapter1
https://www.youtube.com/watch?v=oQ9FwkhUN1s
http://cgi.tutorial.codepoint.net/file-upload
Also if you are uploading images to an ec2 linux server then the folder you want to upload your files into must have the permissions drwxrwxrwt.
chmod 777 -R myfolder
chmod o+t -R myfolder
this worked for me
Referred from here
I'm trying to set up a file upload web form that is processed by a python script. When I select a file and click upload, it says that no file was uploaded. The file field of the fileitem object is None. This script is running on a lighthttpd server.
The code for the script is here:
#!/usr/bin/env python
import cgi, os
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
# A nested FieldStorage instance holds the file
fileitem = form['filename']
print "----"
print "filename", fileitem.filename
print "file", fileitem.file
print "----"
message = ''
if fileitem.file:
# It's an uploaded file; count lines
linecount = 0
while 1:
line = fileitem.file.readline()
if not line: break
linecount = linecount + 1
message = linecount
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('/var/cache/lighttpd/uploads/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message += 'No file was uploaded'
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
The html file is here:
<html>
<head>
<title>RepRap Pinter</title>
</head>
<body>
<H1>RepRap Printer</H1>
<form action="cgi-bin/start_print.py" method="post" encrypt="multipart/form-data">
<p><input type="file" name="filename" id="file"></p>
<p><input type="submit" value="Upload"></p>
</form>
</body>
</html>
And the output is:
----
filename None
file None
----
Content-Type: text/html
<html><body>
<p>No file was uploaded</p>
</body></html>
Any ideas as to why the file isn't being uploaded?
Your problem seems to be here:
<form ... encrypt="multipart/form-data">
The attribute you are looking for isn't encrypt, it's enctype. Since you are missing the correct parameter your encoding isn't multipart-formdata so file uploads are ignored.
You are using the wrong attribute name:
<form action="cgi-bin/start_print.py" method="post" encrypt="multipart/form-data">
The correct attribute is enctype, not encrypt:
<form action="cgi-bin/start_print.py" method="post" enctype="multipart/form-data">