convert html file to BytesIO then pass as Flask variable - python

I'm trying to convert a HTML file to BytesIO so that I don't need to write the file in the filesystem and get it from memory instead. I've read this about converting image to BytesIO however I can't apply it to HTML file.
I'm using Flask as my framework.
What i have tried:
buffer = io.BytesIO()
merged_df.to_html(buffer, encoding = 'utf-8', table_uuid = 'seasonality_table')
buffer.seek(0)
html_memory = base64.b64encode(buffer.getvalue())
return render_template('summary_01.html', html_data = html_memory.decode('utf-8'))
then in the HTML code which I want to output the html file:
<img id="picture" src="data:html;base64, {{ html_data }}">
Error message I got =
TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO

First: using <img> to display HTML is totally wrong idea.
Tag <img> is only for images like PNG, JPG, etc.
You can get directly HTML using to_html() without filename
html = merged_df.to_html(table_id='seasonality_table')
and send this as HTML
return render_template('summary_01.html', html_data=html)
and you need safe to display it as HTML
{{ html_data | safe }}
BTW:
If you want to put data as file for downloading then you should use <a> instead of <img> and it may need application/octet-stream instead of html to start downloading it.
html = merged_df.to_html(table_id='seasonality_table')
html = base64.b64encode(html.encode('utf-8')).decode('utf-8')
return render_template('summary_01.html', html_data=html)
DOWNLOAD
Minimal working example
from flask import Flask, render_template_string
import pandas as pd
import base64
app = Flask(__name__)
#app.route('/')
def index():
data = {
'A': [1,2,3],
'B': [4,5,6],
'C': [7,8,9]
}
df = pd.DataFrame(data)
html = df.to_html(table_id='seasonality_table')
html_base64 = base64.b64encode(html.encode()).decode()
return render_template_string('''<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
{{ html_data | safe }}
DOWNLOAD
</body>
</html>''', html_data=html, html_base64=html_base64)
if __name__ == '__main__':
#app.debug = True
#app.run(threaded=False, processes=3)
#app.run(use_reloader=False)
app.run()

Related

File reading with Python

I have a system to load image files from html but once I select my file and load it from the front end I need a python api to read that image file I select. How can I connect python to my html?
So, to be specific it would be to load an image file with html and have my python api (I use flask) download it and read it to extract data.enter image description here
The html to load the file would be:
<form action="" method="POST" enctype=multipart/form-data>
<div class="col-md-6">
<input type="file" name="file">
<input class="button button-block button-primary" type="submit" value="Upload">
</div>
</form>
The python API to download and read the file would be:
import os
from flask import Flask, render_template, request
from werkzeug import secure_filename
from PIL import Image
# instance of the Flask object
app = Flask(__name__)
# Carpeta de subida
app.config['UPLOAD_FOLDER'] = './Archivos GTiff'
#app.route("/")
#app.route("imgeo/upload-img.html")
def upload_file():
# render the template "upload-img.html"
return render_template('upload-img.html')
#app.route('imgeo/upload-img.html')
def viewer():
"""Show a map to view the GeoJSON returned from a ImGeo endpoint"""
return render_template('imgeo/upload-img.html')
#app.route("imgeo/upload-img.html", methods=['POST'])
def uploader():
if request.method == 'POST':
# we get the file from the "file" input
f = request.files['archivo']
filename = secure_filename(f.filename)
# Save the file in the directory "tiff files".
f.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# We return a satisfactory answer
return "<h1>File uploaded successfully</h1>"
if __name__ == '__main__':
# Start the application
app.run(debug=True)
You could try to encode your image in base64 with JavaScript, send the result with a POST request, and then (in Python) decode it. Check out these two threads:
How can I convert an image into Base64 string using JavaScript? (JavaScript)
Convert string in base64 to image and save on filesystem (Python)
Here is a similar question too:
Sending an image from html to python script through CGI

How to write input from input box from a flask website into a csv or txt file

I have a basic flask website and I would like to know how to write the input from a basic input box into a csv or txt file. I thought my code would work but all it did was create a blank csv file.
My code:
from flask import Flask, request, render_template
import csv
import io
app = Flask(__name__)
f = open('test.csv')
outFile = open('containers.csv', 'w')
free = csv.reader(f)
outFile.write("number" + '\n')
#app.route('/')
def my_form():
return render_template('form.html')
#app.route('/', methods=['POST'])
def my_form_post():
text = request.form['u']
marker = str(text)
return "You inputed " + text
for row in free
outFile.write(marker + '\n')
f.close()
outFile.close()
if __name__ == "__main__":
app.run()
My html code is:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Input</title>
</head>
<body>
<form method="POST">
<p>Input</p><br>
<input name='u'>
<input type='submit'>
</form>
</body>
</html>
I'm pretty sure the problem is in the python section but I don't know what's going wrong
To write to a text file, why not define a function like:
def write_file(data):
with open('containers.txt', 'a') as f:
f.write(data + '\n')
Putting the open function within the with statement, means the f object is available within that block. The file is also automatically closed when the block finishes.
Then you could have a single view function which handles both rendering the form, and accepting the posted result:
#app.route('/', methods = ['GET','POST'])
def my_form():
if request.method=='POST':
text = request.form['u']
write_file(text)
return "You inputed " + text
elif request.method=="GET":
return render_template('form.html')
You should also add an action attribute to the form start tag:
<form method='POST' action='{{ url_for("my_form") }}'>
Now the form will submit to the correct endpoint, even if you change the endpoint which is assigned to the my_form function.

'Download simulation data' link on html using flask app

I am reading user inputs and sending them for processing. After processing, the results are displayed. Along with the results I want a link on webpage to be able to download the data as a csv file. My function to process inputs looks as follows.
#app.route('/process', methods=['POST'])
def process_data():
# create csv_file
return render_template("results.html", data=csv_file)
results.html has following line.
<p> <large>Download simulation data </large></p>
This link is correctly displayed on the webpage. My function to download the data looks as follows.
#app.route('/download/<filename>')
def download(filename):
response = make_response(filename)
response.headers["Content-Disposition"] = "attachment; filename=Simulation.csv"
response.headers["Content-Type"] = "text/csv"
return response
Clicking the download link, I get '414 Request-URI Too Large'.
Is there a better solution for passing data from flask to html to flask again?
I can see that my entire data are appended to url, can I somehow avoid that?
Is it possible to directly pass response while rendering results.html and make it downloadable?
UPDATE
I learnt that putting data in url is a bad idea. Instead I can use dataurl by encoding the data and then use dataurl for csv in href tag of html.
buffer = StringIO()
dataframe.to_csv(buffer, index=False)
buffer.seek(0)
data_str = base64.b64encode(buffer.getvalue().encode('utf8')).decode('ascii')
url = "data:text/csv; base64,{}".format(data_str)
html looks like as follows.
<a download="SSW_Simulation.csv" href="{{ data_url }}">download</a>
However this solution does not work in internet explorer I guess because urls for data are not supported. Should I be saving the csv file somewhere and pass that filename to html? so that when prompted, I can fetch it from the temporary location and download using make_response? I would prefer not to save the file to the disk.
Handling the data in javascript solved the problem as suggested by #Jeronimo. json string was passed to html page.
import json
#app.route('/process', methods=['POST'])
def process_data():
# create csv_file
data = json.dumps(csv_file)
return render_template("results.html", data=data)
Javascript suggested in this answer was added to html and along with download button.
<button onclick="download({{ data }}, 'myfile.csv', 'text/csv')">download data</button>

How can I showcase all images in particular files with Flask?

I want to make a webpage with Flask which enables me to search images according to some keywords and return two relevant images in the webpage.
And, assume the keyword is 'Steve jobs' and these images that are related to 'Steve jobs' will be scraped by Google Search and stored in a file called 'Steve jobs'.
But I still cannot display images from my file and return a blank page.
hello.py
#app.route("/about",methods=['GET', 'POST'])
def about():
...
DIR = os.path.join(os.getcwd())
DIR = os.path.join(DIR, query.split()[0])
...
def show_index():
for i,(img,Type) in enumerate(ActualImages[:2]):
try:
req = urllib.request.Request(img, headers=header)
raw_img = urllib.request.urlopen(req).read()
cntr = len([i for i in os.listdir(DIR) if image_type in i]) + 1
print(cntr)
if len(Type)==0:
f = open(os.path.join(DIR,image_type + "_"+ str(cntr)+".jpg"),'wb')
else:
f = open(os.path.join(DIR,image_type + "_"+ str(cntr)+"."+Type),'wb')
f.write(raw_img)
f.close()
except Exception as e:
print('>>> Could not load: '+img)
print(e)
return f
return render_template('about.html', f = f)
about.html
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<img src="{{f}}" alt="f">
</body>
</html>
A typical HTML image tag looks like so:
<img src="/path/image.gif" alt="My Image"/>
As you can see, the src attribute contains a URL telling the browser where to find the image. It will go off and download the image from there. It doesn't contain the image itself. Your code appears to be trying to load the image file's content into the HTML, and that won't work.
(Note - it is possible to directly embed images into HTML, but it's pretty unusual, so I won't talk about that.)
Given that, what you need to is to put the images somewhere, and serve and refer to them as per the answer to How do i link to images not in Static folder in flask.

Image Uploading Python

I wants to browse image & upload image to folder in my application using python
when i click on submit button its shows me http://www.domain.com/store_mp3_view & image is not uploaded
html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
<form action="/store_mp3_view" method="post" accept-charset="utf-8"
enctype="multipart/form-data">
<label for="mp3">Mp3</label>
<input id="mp3" name="mp3" type="file" value="" />
<input type="submit" value="submit" />
</form>
</body>
</html>
python file code
import os
import uuid
from pyramid.response import Response
def store_mp3_view(request):
# filename contains the name of the file in string format.
#
# WARNING: this example does not deal with the fact that IE sends an
# absolute file path as the filename. This example is naive; it
# trusts user input.
filename = request.POST['mp3'].filename
# ``input_file`` contains the actual file data which needs to be
# stored somewhere.
input_file = request.POST['mp3'].file
# Note that we are generating our own filename instead of trusting
# the incoming filename since that might result in insecure paths.
# Please note that in a real application you would not use /tmp,
# and if you write to an untrusted location you will need to do
# some extra work to prevent symlink attacks.
file_path = os.path.join(/files, '%s.mp3' % uuid.uuid4())
# We first write to a temporary file to prevent incomplete files from
# being used.
temp_file_path = file_path + '~'
output_file = open(temp_file_path, 'wb')
# Finally write the data to a temporary file
input_file.seek(0)
while True:
data = input_file.read(2<<16)
if not data:
break
output_file.write(data)
# If your data is really critical you may want to force it to disk first
# using output_file.flush(); os.fsync(output_file.fileno())
output_file.close()
# Now that we know the file has been fully saved to disk move it into place.
os.rename(temp_file_path, file_path)
return Response('OK')
return Response('OK')
You can use models filefield inside models.py
class Document(models.Model):
docfile = models.FileField(upload_to='documents/', max_length=5234,blank=True, null=True,)
corresponding forms.py
class DocumentForm(forms.Form):
docfile = forms.FileField(label='', show_hidden_initial='none',required=True,)
Inside views.py
if request.FILES.has_key('your_fileName'):
newdoc = Document(docfile = request.FILES['your_fileName'])
newdoc.save()
I got it working with above code, hope it helps
With this code you can upload multiple files
def insert_file(self):
for i in request.FILES.getlist('mp3'):
fileName = i.name
out_file = open(fileName,'w')
out_file.write(i.read())
return HttpResponse('Inserted Successfully')

Categories

Resources