I have started learning flask for web development and experimenting with it since I have a website in mind I would like to create.
My thought has been to create a homepage showing some data that will be updated using cURL or the requests python library. I have some other python code that generates the data to be displayed and I would like to use the POST request for sending a dictionary with the generated information to the server and update the homepage with that new info.
A rather simplistic but comprehensive version of what I have tried so far:
from flask import Flask, redirect, url_for, render_template, request
app = Flask(__name__)
#app.route("/", methods=["POST", "GET"])
def home():
if request.method == "POST":
data = request.form["data"]
return render_template("index.html", content=data)
else:
return render_template("index.html", content="initial_data")
if __name__ == "__main__":
app.run(debug=True)
The code for index.html
<!doctype html>
<html>
<head>
<title>Home Page</title>
</head>
<body>
{{content}}
</body>
</html>
So I would like to send a POST request with some new data to the server and update the webpage with that new data.
import requests
payload = {'data': 'new_data'}
r = requests.post("http://localhost:5000/", data=payload)
All of the above doesn't succeed in updating the data in the webpage when I send a request, it just stays the same. Am I totally off course? Is this even possible in the way I have thought of?
Any comment is much appreciated, thank you.
data is staying the same because it's being reassigned each time as a local variable. When a POST request happens, the variable is created, passed to the template, then destroyed as it goes out of scope.
Try this as an experiment in showing how a variable might persist between page loads, though only until the server restarts:
from flask import Flask, redirect, url_for, render_template, request
app = Flask(__name__)
app_state = {
'data': 'Initial Data'
}
#app.route("/", methods=["POST", "GET"])
def home():
if request.method == "POST":
app_state['data'] = request.form['data']
return render_template("index.html", content=app_state['data'])
if __name__ == "__main__":
app.run(debug=True)
In that example, you're creating a global dictionary, app_date, and updating a key on it every time the user sends a POST request to / with a form payload of data.
Then, we return the template with the content of the dictionary item.
A Few Notes
The implementation I provided would still be vulnerable to race conditions if two people make simultaneous changes.
For this kind of thing, you'll usually want a more persistent solution, like a database.
Related
I am learning Flask. I wrote the basic code and I want the submitted text to display in the same page. I already wrote the html and connected it. How can I do this?
from flask import Flask, redirect, url_for,render_template, request
app = Flask(name)
#app.route("/", methods=["POST", "GET"])
def home():
if request.method == "POST":
user = request.form["nm"]
return redirect(url_for("/", user))
else:
return render_template("login.html")
if name == ("main"):
app.run(debug=True)
I've noticed that you've taken the code from Python Basics. Indeed they do not show how to format the HTML template of the redirect.
Luckily, they offer a tutorial that shows you how to feed retrieved data to an HTML template using Jinja2. This tutorial can be found here. In essence, you can use {{ variable }} in your HTML template. In Flask, you will have to specify the variable as argument in the render_template function.
Minimal example:
# app.py
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
variable = request.form['variable']
return render_template("result.html", variable=variable)
<!-- result.html -->
<p> This is your variable: {{ variable }} </p>
I advice you to also check out both the Flask and Jinja2 documentation, as they offer plenty comprehensive examples of how to work with callbacks and HTML templating.
I have been coding a flask app that works perfectly fine while running locally, but while hosting the app a strange bug occurs. After I've posted a string to the server it responds with the expected page, but when I repeat it with another request (without restarting the server) the same page as earlier is displayed yet again.
It seems like the render_template does not update the changes I've done in the HTML file after it already has rendered the template, even though the command is run again.
#app.route("/", methods=['POST', 'GET'])
def index():
if request.method == 'POST':
content = str(request.form['content'])
# Some code that changes the "output.html" page based on the user input
return render_template('output.html')
else:
return render_template("index.html")
Why not use redirect instead of render_template in your if condition, like this:
#app.route("/", methods=['POST', 'GET'])
def index():
if request.method == 'POST':
content = str(request.form['content'])
return redirect(url_for('output.html'))
else:
return render_template("index.html")
I found the solution. Apparently the page doesn't update if it has the same URL as before even though a new template is rendered under the same URL. The solution was to make a dynamic URL.
I am very new to Flask and Web development so sorry in advanced if I use incorrect terms.
I am trying to create a webpage using Python and Flask. To do so, I have the following:
from flask import Flask, request, render_template, redirect, url_for
from flask_assets import Environment, Bundle
app = Flask(__name__)
assets = Environment(app)
#app.route("/", methods=["GET", "POST"])
def login():
# Code to do the login
error = None
if request.method == 'POST':
# code checking the passwords. if correct:
return render_template('index.html')
# else:
# error
return render_template('login.html', error = error)
What this snippet of code does is to load the login.html where the user is asked to put an username and password and after checking if they are the ones expected, it loads index.html where the user can upload his or her data. Once the data is submitted a new function is called:
#app.route('/transform', methods=["POST"])
def transform():
f = request.files['data_file']
if not f:
return "No file"
# code
return render_template('message.html')
The problem is that while in local the message.html gets display once transform has finished, in the server it doesn't appear although the function eventually does what it's expected to do. The other two templates are correctly displayed both in local and in the server. Could it be due to be in a different route?
The index.html is defined with action='\transform', in case it may give a hint.
Any idea of why could this be happening?
I am trying to render an HTML page on local host with restful flask api. The content of HTML page gets displayed as string with "" rather than the page.
class data(Resource):
def get(self):
#return "Welcome!"
return render_template('index.html')
api.add_resource(data,'/')
My index.html file contains the following content
<!DOCTYPE html>
<html>
<body>
<h1>Welcome to the site!</h1>
</body>
</html>
After running the code, on the webpage(http://localhost:5000/) I get the following content
"<!DOCTYPE html>\n<html>\n<body>\n<h1>Welcome to the Data Hosting Service</h1>\n</body>\n</html>"
On the other hand,It is returning the text "Welcome!" normally. Can you help me ?
Update:
With the help from users, I have fixed this problem by changing the response type as follows,
from flask import Response, render_template
return Response(render_template('index.html'),mimetype='text/html')
You may need import make_repsone from flask to render your html with headers information.
from flask import make_response, render_template
headers = {'Content-Type': 'text/html'}
return make_response(render_template('index.html'),200,headers)
Hope this could be helpful.
I'm writing a web-app using flask, python and HTML. My issue is that the first time I load the a webpage, I get the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
I'm able to get the page to load eventually by "tricking" first running it without any flask.request.form calls, and then putting them back in (details below). Something must be going wrong in my initialization. I'm new to flask and using python with HTML.
Assume I'm working from a directory called example. I have a python script called test.py and an HTML template called test.html with the following directory structure:
\example\test.py
\example\templates\test.html
My python script test.py is:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
and my HTML in test.html is
<html>
<head>
</head>
<body>
<form action="/" method="post">
Enter something into the box:
<input type="text" name="result"/><br>
<input type="submit" value="Execute!"/>
</form>
</body>
</html>
Steps to reproduce the error
1: Run the test.py script, and open up the URL in a browser
Running on http://127.0.0.1:5000/
You should see the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
2: Comment out the first 2 lines of the def get(self) function and uncomment the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
# result = flask.request.form['result']
# return flask.render_template('test.html', result=result)
return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
3: Refresh the URL, and you will see that things work (though I ultimately want to be able to return the value of result
4: Now, switch the lines that are commented out again. I.e, uncomment the first 2 lines of the def get(self) function and comment out the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
5: Refresh the URL and now you see things will be working as desired.
This is just a toy example illustrating the real problem exhibiting this weird behavior of how I have to "trick" my browser into showing me this webpage. The
The issue here is that you are attempting to access POSTed variables in a method that will only handle GET requests. When you attempt to access a query string or POST parameter that is not set Flask will, by default, raise a BadRequest error (because you are asking for something that the person hitting the page did not supply).
What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.
If you need to access a variable from either request.args (GET) or request.form (POST) and you don't need it to be set use the get method to get the value if it is there (or None if it is not set.
# Will default to None
your_var = request.form.get("some_key")
# Alternately:
your_var = request.form.get("some_key", "alternate_default_value")
Here's an alternate way of structuring your code:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
app.debug = True
class View(flask.views.MethodView):
def get(self):
"""Enable user to provide us with input"""
return self._default_actions()
def post(self):
"""Map user input to our program's inputs - display errors if required"""
result = flask.request.form['result']
# Alternately, if `result` is not *required*
# result = flask.request.form.get("result")
return self._default_actions(result=result)
def _default_actions(self, result=None):
"""Deal with the meat of the matter, taking in whatever params we need
to get or process our information"""
if result is None:
return flask.render_template("test.html")
else:
return flask.render_template("test.html", result=result)
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
if __name__ == "__main__":
app.run()