I have a dataframe that contains a column containing <canvas> something </canvas> element. In a flask application, I passed this data to a template using df.to_html(), but it never is working and always shows the <canvas> within displayed html table.
To enable showing the characters <, >, and & signs in to_html() method, we need to change the escape attribute to False. Because by default to_html method converts the characters <, >, and & to HTML-safe sequences. Also we need to use safe filter in the template file to show the tags inside the table.
As you have already found how to show the HTML properly in Flask template, I am giving an example of the operation for future readers.
app.py contains a dataframe with html tags which we want to render in the template:
import pandas as pd
from flask import Flask, render_template
def get_panda_data():
tags = ["<h1>Example header</h1>",
'<div style="color: red;">Example div</div>',
'<input type="text" name="example_form" \
placeholder="Example input form">'
]
pd.set_option('display.max_colwidth', -1)
tags_frame = pd.DataFrame(tags, columns = ["Tag Example"])
tags_html = tags_frame.to_html(escape=False)
return tags_html
app = Flask(__name__)
#app.route('/')
def index():
html_data = get_panda_data()
return render_template("dataframe_example.html", html_data = html_data)
if __name__ == '__main__':
app.run(debug = True)
Then in template file which is dataframe_example.html we can easily show the data table generated by pandas to_html method:
<!DOCTYPE html>
<html>
<head>
<title>Dataframe Flask Example</title>
</head>
<body>
<h1>Dataframe Flask Example</h1>
{{ html_data | safe }}
</body>
</html>
The output looks like:
I realized that I had to utilize the option to_html(escape=False) to solve this problem
Related
This question already has answers here:
How can I submit a form using JavaScript?
(10 answers)
replacing div content with javascript
(6 answers)
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
Here is my directory setup:
/output
/text_file.txt
/templates
/index.html
app.py
read.py
Here is my index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div>
</div>
<button> Read</button>
</body>
</html>
Here is my app.py:
from flask import Flask, render_template, jsonify, redirect, request
import fitz
from read import read_txt
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/abc')
def link():
return read_txt("text_file.txt")
if __name__ == "__main__":
app.run(port=5000, debug = True)
and this is my read.py:
import os
def read_txt(file):
doc = os.getcwd()+"\\output\\"+file
with open(doc,"r") as f:
text = f.read()
return text
Question: I am reading a txt file in python. I want to make an html page with a button READ which when clicked will show me the content of txt file on the same page(same route path: http://127.0.0.1:5000/ ), inside that defined div component.
But for now, when I click on button, output is showing in another route (http://127.0.0.1:5000/abc).
I am really struggling with this. I read somewhere that we can use jinja template but I am not sure how to do this.
I am sorry if it is a very basic question but I am a begineer and unable to figure it out.
Thank you.
I am trying to display a timer of 5minutes (for example). I am using flask.
I know it could be good to use javascript but I really want to do it with python.
I have two issues:
First issue: display of the timer - issue to overwrite
I wrote a function for the timer in python which is supposed to display (for example for 50 seconds):
00:50 then remove 00:50 and have00:49, and so on...
But it is displaying:
00:50
00:49
00:48
...
Here is my code: screen.py
from flask import Flask, Response, request, render_template, render_template_string, stream_with_context
import time
app = Flask(__name__)
timing=0
#app.route('/content', methods=['POST', 'GET']) # render the content a url differnt from index. This will be streamed into the iframe
def content():
global timing
timing = 10
# if request.form.get("submit"):
# timing = request.form['timing']
# print(timing)
def countdown(t):
while t:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
print(timer, end="\r")
yield timer
time.sleep(1)
t -= 1
# return timer
return app.response_class(countdown(timing)) #at the moment the time value is hardcoded in the function just for simplicity
# return render_template('display.html')
#app.route('/')
def index():
value = "Bonjour"
title_html = value
return render_template('display.html', message=title_html) # render a template at the index. The content will be embedded in this template
if __name__ == '__main__':
app.run(use_reloader=False)
I would like to find the equivalence of print(timer, end="\r") for yield in order to overwrite the value of timer and not see all the results when it's decreasing. I hope my explanation is clear.
Second issue: Input value of the timer
As you can see in my code screen.py, my value for timing is hardcoded timing=10. But I would like to allow the user to enter the value he wants in input like that:
if request.form.get("submit"):
timing = request.form['timing']
print(timing)
You can see these lines in screen.py, I commented them to leave timing=10 because when I write these lines I obtain the following error:
Method Not Allowed
The method is not allowed for the requested URL.
127.0.0.1 - - [02/Aug/2021 12:50:26] "POST / HTTP/1.1" 405 -
Here is the HTML Code linked to my python code display.html:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href='/static/main.css'/>
<title>your dish</title>
</head>
<body>
<h1>{{message}}! Here are some informations about your dish:</h1>
<h2> countdown </h2>
<!-- <p>{{message}}</p> -->
<form method="POST" action=".">
<p><input name="timing" value="{{timing}}" placeholder="Enter your time"></p>
<input type="submit" name="submit" value="submit">
</form>
<div>
<iframe frameborder="0" noresize="noresize"
style='background: transparent; width: 100%; height:100%;' src="{{ url_for('content')}}"></iframe>
</div>
</body>
</html>
How can I avoid this error and take into consideration the value entered by the user in the input field of my display.html?
I tryed to run your script locally but I am not sure where do you expect to see the timer; I assume you used the countdown func from here.
I would like to propose you a different approach: stream dynamically the counter to the web page using an iframe:
from flask import Flask, render_template, Response
import time
app = Flask(__name__)
#app.route('/content') # render the content a url differnt from index. This will be streamed into the iframe
def content():
def timer(t):
for i in range(t):
time.sleep(5) #put 60 here if you want to have seconds
yield str(i)
return Response(timer(10), mimetype='text/html') #at the moment the time value is hardcoded in the function just for simplicity
#app.route('/')
def index():
return render_template('test.html.jinja') # render a template at the index. The content will be embedded in this template
if __name__ == '__main__':
app.run(use_reloader=False)
then add an iframe where do you prefer in your html
<!doctype html>
<head>
<title>Title</title>
</head>
<body>
<h2> countdown </h2>
<div>
<iframe frameborder="0" noresize="noresize"
style='background: transparent; width: 100%; height:100%;' src="{{ url_for('content')}}"></iframe>
</div>
</body>
The result will be a dynamic countdown on your web-page
countdown
0123456789
you can see it done quick and dirty here on my repl
While it's not tuned around your application yet, (and not particularly beautiful graphically) you can modify the function to accept an input from the user with a form (I see you actually did already in your app), or also tune the countdown function directly.
t = request.form['t']
and adding to your html the form
<form method="post" action=".">
<p><input name="t" placeholder="your time"/></p>
<p><input type="submit" value="Submit"/></p>
</form>
You have the same route #app.route("/") appearing 3 times. The system will pick the first one which simply displays display.html. And I suspect even that will currently not work because your page is expecting values for message, timing but those attributes don't exist in your first route.
You should try something like
#app.route("/", methods=['POST', 'GET'])
def display():
page = 'display.html'
params = {"message":"", "timing":0} # initialize values for both message and timing. These will be returned when user loads the page (a GET call)
if request.method == 'POST':
timing = request.values.get("timing")
# do whatever processing you want
params["timing"] = <your computed value>
params["message"] = <your message>
params["message_2"] = <your other message>
return render_template(page, **params)
Delete all the other routes you have for #app.route("/")
I would like to build a simple web application that able to display the results of parsing YAML files using python and Flask. I've been written the code and it works, but the results not the same as expected.
Here's my code:
import yaml
from flask import Flask, request, render_template, redirect, url_for
#from pathlib import Path
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def my_form_post():
#path=Path('/Users/Devie Andriyani/EditFlask/categories.yaml') # set the path to your file here
#if not path.exists():path.touch()
if request.method == 'POST':
#with open(path, 'w') as f:
#f.write(request.form.get('Text Area',None))
return redirect(url_for('my_form_post'))
#with open(r'C:\Users\Devie Andriyani/EditFlask/categories.yaml') as f:
#my_dict = yaml.safe_load(f)
a_yaml_file = open("categories.yaml")
parsed_yaml_file = yaml.load(a_yaml_file, Loader=yaml.FullLoader)
print(parsed_yaml_file["countries"])
print(parsed_yaml_file["sports"])
return render_template('index.html')
if __name__ == '__main__':
app.debug = True
app.run()
And here's my HTML code:
<!DOCTYPE html>
<head>
<title>Hello</title>
</head>
<body>
<form action="" method="POST">
<p>Text Area</p>
<p><textarea name="Text Area" rows="20" cols="50" value={{categories}}></textarea>
</p>
<input type="submit">
</form>
</body>
</html>
And here's my YAML file:
sports:
- soccer
- football
- basketball
- cricket
- hockey
- table tennis
countries:
- Pakistan
- USA
- India
- China
- Germany
- France
- Spain
And here's the result:
I want the results of parsing show on the text area
You opened the file, saved it in a variable, but you didn't pass that to the front-end. You just print it, that why it is printing in the console. You have to pass this to the frontend.
parsed_yaml_file = yaml.load(a_yaml_file, Loader=yaml.FullLoader)
# print(parsed_yaml_file["countries"]) # this will print in console not in frontend
# print(parsed_yaml_file["sports"]) # this too
return render_template('index.html', yml = parsed_yaml_file)
Here I passed the file content parsed_yaml_file to the frontend with the name yml. So we can access this in the frontend now. But one problem we have. yaml.load will return a dictionary. And if you want to display as a dictionary, then no worries. But if you want to display as YAML format itself, then you should not convert it into yaml. You directly pass the file a_yaml_file.
Suppose if you want yaml output, (hope you passed yml = a_yaml_file) then in frontend you have to use pre tag.
<pre>{{ yml }}</pre>
If you want a dictionary, (pass yml = parsed_yaml_file) then just use this in frontend
{{ yml }}
This is my sample HTML file
<html>
<head>
<title>
</title>
</head>
<body>
<form action="">
Value a:<br>
<input type="text" name="Va">
<br>
Value b:<br>
<input type="text" name="Vb">
<br><br>
<input type="submit">
</form>
<textarea rows="4" cols="10">
</textarea>
<p>
</p>
</body>
</html>
And a given template Tornado server code:(I also need help on the explanation of each section of the following code)
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.gen
import tornado.options
tornado.options.parse_command_line()
class APIHandler(tornado.web.RequestHandler):
#tornado.web.asynchronous
def get(self):
self.render('template.html')
#tornado.gen.engine
def post(self):
try:
num = int(self.get_argument('num'))
except:
num = 5
self.render('template.html')
app = tornado.web.Application([(r"/next_rec",APIHandler),])
if __name__ == "__main__":
server = tornado.httpserver.HTTPServer(app)
server.bind(48763)
server.start(5)
tornado.ioloop.IOLoop.current().start()
and finally my python code:
if __name__ == '__main__':
a = int(raw_input())
b = int(raw_input())
print a+b
I am using a simple 'a+b' function to test out this feature. But my problem is I can't figure out a way to link them together. So my ultimate goal is to click on the "Submit" button on the HTML, pass on two values to the Tornado server, use it as input in my python script and finally show the output in the text area of the HTML or on another page. I'm know there are tons of information on the web, but I'm completely new to Tornado (near 0 knowledge) and most of them I can't really understand. Help on methods or keywords for search is much appreciated, thank you very much. (please keep answers as basic as possible, it will help a lot, thanks!)
First of all you should check the official documentation. It is quite simple and it targets the newcomers.
Also in this short guide, the sections of a similar code as your is being explained with simplicity.
Now for your code:
On your template you need to specify that the form should send a post request on submit by adding <form method="post" id="sum_form">
Also you need to make sure that you will be submit the data added in the form on an event: $("#sum_form").submit();
On your post method you need to read the passed numbers from your client's form, add them and then send them back to the template as a parameter.
For example:
def post(self):
numA = int(self.get_argument('Va'))
numB = int(self.get_argument('VB'))
sumAB = numA + numB
self.render('template.html',sumAB=sumAB)
In you template.html you need to add a field where you will display the passed sum as a jinja variable : {{sumAB}}
What is the simplest way to display the Python ystockquote (http://goldb.org/ystockquote.html) module output in HTML? I am creating an HTML dashboard which will be run locally on my computer and want to insert the stock output results into the designated HTML placeholders. I am hoping that because it is local I can avoid many CGI and server requirements.
I would use a templating system (see the Python wiki article). jinja is a good choice if you don't have any particular preferences. This would allow you to write HTML augmented with expansion of variables, control flow, etc. which greatly simplifies producing HTML automatically.
You can simply write the rendered HTML to a file and open it in a browser, which should prevent you from needing a webserver (though running python -m SimpleHTTPServer in the directory containing the HTML docs will make them available under http://localhost:8000)
Here is a simple server built using web.py (I have been playing with this for a while now, so this was a fun question to answer)
import web
import ystockquote
urls = (
'/', 'index'
)
app = web.application(urls, globals())
class index:
def POST(self):
history = ystockquote.get_historical_prices(web.input()['stock'], web.input()['start'], web.input()['end'])
head = history[0]
html = '<html><head><link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"><body><table class="table table-striped table-bordered table-hover"><thead><tr><th>{}<th>{}<th>{}<th>{}<th>{}<th>{}<th>{}<tbody>'.format(*head)
for row in history[1:]:
html += "<tr><td>{}<td>{}<td>{}<td>{}<td>{}<td>{}<td>{}".format(*row)
return html
def GET(self):
return """<html>
<head><link href='//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css' rel='stylesheet'>
<body>
<form method='POST' action='/'><fieldset>
Symbol <input type='input' name='stock' value='GOOG'/><br/>
From <input type='input' name='start' value='20130101'/><br/>
To <input type='input' name='end' value='20130506'/><br/>
<input type='submit' class='btn'/></fieldset></form>"""
if __name__ == "__main__":
app.run()