Here is my code in myclass.py
class Pdf():
def render_pdf(self,name,html):
from xhtml2pdf import pisa
from StringIO import StringIO
pdf = StringIO()
pisa.CreatePDF(StringIO(html), pdf)
return pdf
And I am calling it in api.py like this
#app.route('/invoice/<business_name>/<tin>', methods=['GET'])
def view_invoice(business_name,tin):
#pdf = StringIO()
html = render_template('certificate.html', business_name=business_name,tin=tin)
file_class = Pdf()
pdf = file_class.render_pdf(business_name,html)
return pdf
But it throws this error
AttributeError: StringIO instance has no __call__ method
The following script worked well for me. Note the changes I made:
Pdf.render_pdf() now returns pdf.getvalue(), a str.
view_invoice() now returns a tuple, so that the Content-Type header can be set.
#!/usr/bin/env python
from flask import Flask, render_template
app = Flask(__name__)
class Pdf():
def render_pdf(self, name, html):
from xhtml2pdf import pisa
from StringIO import StringIO
pdf = StringIO()
pisa.CreatePDF(StringIO(html), pdf)
return pdf.getvalue()
#app.route('/invoice/<business_name>/<tin>', methods=['GET'])
def view_invoice(business_name, tin):
#pdf = StringIO()
html = render_template(
'certificate.html', business_name=business_name, tin=tin)
file_class = Pdf()
pdf = file_class.render_pdf(business_name, html)
headers = {
'content-type': 'application.pdf',
'content-disposition': 'attachment; filename=certificate.pdf'}
return pdf, 200, headers
if __name__ == '__main__':
app.run(debug=True)
Related
Hi I want to upload a excel file form fronted and in back end i want to read all contents of that Excel File and store that in my database
#app.route('/getfile', methods=['POST'])
def getfile():
try:
file = request.files['file']
foo=file.filename
dframe = pd.read_excel(foo)
return dframe
except Exception as ex:
return ex
i am getting filename and from panda i want to read that excel file data but its showing no such directory exists
from flask import Flask, request, jsonify
import flask_excel as excel
app = Flask(__name__)
import json
import xlrd
import os
import pandas as pd
from collections import OrderedDict
from pathlib import Path
from flask_cors import CORS,cross_origin
from json import loads
import pandas as pd
wsgi_app = app.wsgi_app
excel.init_excel(app)
code 1
#app.route("/upload", methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
foo = request.get_array(field_name='file')
# data = json.dumps(foo, )
# for i in data[1:]:
return jsonify({"result":foo })
#code 2
#app.route('/getfile', methods=['POST'])
def getfile():
try:
file = request.files['file']
foo=file.filename
dframe = pd.read_excel(foo)
return dframe
except Exception as ex:
return ex
1st code giving me 404 exception and 2nd code giving me "No such Directory exits"
can anybody help me out in this reading the content of excel file
from flask import Flask, request, jsonify
from tablib import Dataset
app = Flask(__name__)
#app.route('/upload', methods=['POST'])
def upload_file():
# I used form data type which means there is a
# "Content-Type: application/x-www-form-urlencoded"
# header in my request
raw_data = request.files['myfile'].read() # In form data, I used "myfile" as key.
dataset = Dataset().load(raw_data)
return jsonify(dataset.export('json'))
if __name__ == '__main__':
app.run(debug=True)
This little snippet is working just fine. You don't need to use a huge data analyzing library to import something to database. But if you insist using pandas, your question needs another answer.
Check out the documentation before doing anything else:
http://flask.pocoo.org/docs/1.0/patterns/fileuploads/
http://docs.python-tablib.org/en/master/tutorial/#importing-data
Try this buddy, you need to read the file first (foo.read()). That way you'll get the un-parsed file, then you need to read this un-parsed file using pandas, like as follows:
#app.route('/getfile', methods=['POST'])
def getfile():
try:
file = request.files['file']
foo=file.filename
unparsedFile = foo.read()
dframe = pd.read_excel(unparsedFile)
return dframe
except Exception as ex:
return ex
I try to download img from url, add it to zip archive and then response this archive by Django HttpResponse.
import os
import requests
import zipfile
from django.http import HttpResponse
url = 'http://some.link/img.jpg'
file = requests.get(url)
data = file.content
rf = open('tmp/pic1.jpg', 'wb')
rf.write(data)
rf.close()
zipf = zipfile.ZipFile('tmp/album.zip', 'w') # This file is ok
filename = os.path.basename(os.path.normpath('tmp/pic1.jpg'))
zipf.write('tmp/pic1.jpg', filename)
zipf.close()
resp = HttpResponse(open('tmp/album.zip', 'rb'))
resp['Content-Disposition'] = 'attachment; filename=album.zip'
resp['Content-Type'] = 'application/zip'
return resp # Got corrupted zip file
When I save file to tmp folder - it's ok, I can extract it.
But when I response this file I get 'Error 1/2/21' on MacOS or Unexpected EOF if I try to open in Atom editor (just for test).
I also used StringIO instead of saving zip file, but it doesn't influence the result.
If you're using Python 3, you'd do it like this:
import os, io, zipfile, requests
from django.http import HttpResponse
# Get file
url = 'https://some.link/img.jpg'
response = requests.get(url)
# Get filename from url
filename = os.path.split(url)[1]
# Create zip
buffer = io.BytesIO()
zip_file = zipfile.ZipFile(buffer, 'w')
zip_file.writestr(filename, response.content)
zip_file.close()
# Return zip
response = HttpResponse(buffer.getvalue())
response['Content-Type'] = 'application/x-zip-compressed'
response['Content-Disposition'] = 'attachment; filename=album.zip'
return response
That's without saving the file. Downloaded file goes directly to io.
To response saved file, use this syntax:
response = HttpResponse(open('path/to/file', 'rb').read())
I want to process a Pandas dataframe and send it to download as a CSV without a temp file. The best way to accomplish this I've seen is to use StringIO. Using the code below, a file downloads with the proper name, however the file is completely blank, and no error is shown. Why doesn't the file contain data?
#app.route('/test_download', methods = ['POST'])
def test_download():
buffer = StringIO()
buffer.write('Just some letters.')
buffer.seek(0)
return send_file(
buffer,
as_attachment=True,
download_name='a_file.txt',
mimetype='text/csv'
)
The issue here is that in Python 3 you need to use StringIO with csv.write and send_file requires BytesIO, so you have to do both.
#app.route('/test_download')
def test_download():
row = ['hello', 'world']
proxy = io.StringIO()
writer = csv.writer(proxy)
writer.writerow(row)
# Creating the byteIO object from the StringIO Object
mem = io.BytesIO()
mem.write(proxy.getvalue().encode())
# seeking was necessary. Python 3.5.2, Flask 0.12.2
mem.seek(0)
proxy.close()
return send_file(
mem,
as_attachment=True,
download_name='test.csv',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name was called attachment_filename.
Use BytesIO to write bytes.
from io import BytesIO
from flask import Flask, send_file
app = Flask(__name__)
#app.route('/test_download', methods=['POST'])
def test_download():
# Use BytesIO instead of StringIO here.
buffer = BytesIO()
buffer.write(b'Just some letters.')
# Or you can encode it to bytes.
# buffer.write('Just some letters.'.encode('utf-8'))
buffer.seek(0)
return send_file(
buffer,
as_attachment=True,
download_name='a_file.txt',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name was called attachment_filename.
make_response
To get Flask to download a csv file to the user, we pass a csv string to the make_response function, which returns a
Response object.
Then we add a Header which tells the browser to accept the file as a download.
The Mimetype also must be set to text/csv in order to get the web browser to save it in something other than an html document.
from flask import Flask, make_response
app = Flask(__name__)
#app.route('/test_download', methods=['POST'])
def test_download():
with StringIO() as buffer:
# forming a StringIO object
buffer = StringIO()
buffer.write('Just some letters.')
# forming a Response object with Headers to return from flask
response = make_response(buffer.getvalue())
response.headers['Content-Disposition'] = 'attachment; filename=namaste.csv'
response.mimetype = 'text/csv'
# return the Response object
return response
P.S. It is preferred to use python's built-in csv library to deal with csv files
References
https://matthewmoisen.com/blog/how-to-download-a-csv-file-in-flask/
https://www.geeksforgeeks.org/stringio-module-in-python/
https://docs.python.org/3/library/csv.html
Namaste 🙏
if someone use python 2.7 with Flask and got the error about the module StringIO by importing it. This post can help you to solve your problem.
If you are importing String IO module, you can just change the import syntax by using this : from io import StringIO instead from StringIO import StringIO.
You can Also use from io import BytesIO if you are using image or some others ressource.
Thank you
I have a function which generates a PDF and I have a Flask website. I would like to combine the two so that when you visit the site, a PDF is generated and downloaded. I am working on combining various bits of code that I don't fully understand. The PDF is generated and downloaded but fails to ever load when I try to open it. What am I missing?
import cStringIO
from reportlab.lib.enums import TA_JUSTIFY
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from flask import make_response, Flask
from reportlab.pdfgen import canvas
app = Flask(__name__)
#app.route('/')
def pdf():
output = cStringIO.StringIO()
doc = SimpleDocTemplate("test.pdf",pagesize=letter)
Story=[]
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
ptext = '<font size=12>test</font>'
Story.append(Paragraph(ptext, styles["Justify"]))
doc.build(Story)
pdf_out = output.getvalue()
output.close()
response = make_response(pdf_out)
response.headers['Content-Disposition'] = "attachment; filename='test.pdf"
response.mimetype = 'application/pdf'
return response
app.run()
You can use Flask's send_file for serving files:
from Flask import send_file
return send_file('test.pdf', as_attachment=True)
With as_attachment=True you can force the client to download the file instead of viewing it inside the browser.
Is it possible to make a zip archive and offer it to download, but still not save a file to the hard drive?
To trigger a download you need to set Content-Disposition header:
from django.http import HttpResponse
from wsgiref.util import FileWrapper
# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response
If you don't want the file on disk you need to use StringIO
import cStringIO as StringIO
myfile = StringIO.StringIO()
while not_finished:
# generate chunk
myfile.write(chunk)
Optionally you can set Content-Length header as well:
response['Content-Length'] = myfile.tell()
You'll be happier creating a temporary file. This saves a lot of memory. When you have more than one or two users concurrently, you'll find the memory saving is very, very important.
You can, however, write to a StringIO object.
>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778
The "buffer" object is file-like with a 778 byte ZIP archive.
Why not make a tar file instead? Like so:
def downloadLogs(req, dir):
response = HttpResponse(content_type='application/x-gzip')
response['Content-Disposition'] = 'attachment; filename=download.tar.gz'
tarred = tarfile.open(fileobj=response, mode='w:gz')
tarred.add(dir)
tarred.close()
return response
Yes, you can use the zipfile module, zlib module or other compression modules to create a zip archive in memory. You can make your view write the zip archive to the HttpResponse object that the Django view returns instead of sending a context to a template. Lastly, you'll need to set the mimetype to the appropriate format to tell the browser to treat the response as a file.
models.py
from django.db import models
class PageHeader(models.Model):
image = models.ImageField(upload_to='uploads')
views.py
from django.http import HttpResponse
from StringIO import StringIO
from models import *
import os, mimetypes, urllib
def random_header_image(request):
header = PageHeader.objects.order_by('?')[0]
image = StringIO(file(header.image.path, "rb").read())
mimetype = mimetypes.guess_type(os.path.basename(header.image.name))[0]
return HttpResponse(image.read(), mimetype=mimetype)
def download_zip(request,file_name):
filePath = '<path>/'+file_name
fsock = open(file_name_with_path,"rb")
response = HttpResponse(fsock, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response
You can replace zip and content type as per your requirement.
Same with in memory tgz archive:
import tarfile
from io import BytesIO
def serve_file(request):
out = BytesIO()
tar = tarfile.open(mode = "w:gz", fileobj = out)
data = 'lala'.encode('utf-8')
file = BytesIO(data)
info = tarfile.TarInfo(name="1.txt")
info.size = len(data)
tar.addfile(tarinfo=info, fileobj=file)
tar.close()
response = HttpResponse(out.getvalue(), content_type='application/tgz')
response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
return response