Flask, Passing User Entered Data Between Views - python

Problem transferring variables across views I tried using sessions and could not get the connection to work. Say I have two pages, a home and page2. I have a flask app that will take user input from the home and print out input on page2.
For example, if you start my app, you will see this as the home page:
This part works fine, I am able to enter a value.
What I want to happen next, is after you click submit, page2 is generated showing what was just entered:
Whatever string value was entered on home should show up in the highlighted portion.
I have the following app.py file:
from flask import Flask, render_template, request, session
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def home():
stringval = ''
if request.method == 'POST' and 'stringval' in request.form:
stringval = request.form.get('stringval')
session["stringvalue_topass"] = stringval
return render_template('page2.html', stringval = stringval)
return render_template("home.html")
#app.route('/page2', methods=['GET', 'POST'])
def page2():
stringvalue_get = session.get('stringvalue_topass')
return render_template('page2.html', stringvalue_get = stringvalue_get)
if __name__ == '__main__':
app.run(debug=True)
The following home.html:
<!doctype html>
<h1>Enter Value </h1>
<div class="main">
<form class="pure-form" method="POST" action="/page2">
stringval:<br>
<input type="text" name="stringval"><br>
<button type="submit" class="pure-button pure-button-primary" value="Submit">Submit!</button>
</form>
</div>
</body>
And the following page2.html
<!doctype html>
<h1>You have selected </h1>
<div class="main">
{% if stringvalue_get %}
<pre>
{% print(stringvalue_get) %}
</pre>
{% endif %}
</div>
</body>

Okay, there are a few issues here. Firstly, the action attribute of your form in home.html is set to "/page2". This means that when the form is submitted, the POST request is going to the /page2 endpoint rather than to the /home endpoint, where you have written the code for handling the form submission. We can fix this by just deleting the action attribute, as this means the form will post to then endpoint that loaded it - in this case /home.
Secondly, Flask sessions cannot be used without setting a secret key to encrypt the session. This can be done by assigning a value to app.secret_key, like so:
app = Flask(__name__)
app.secret_key = b"my_secret_key"
Finally, instead of passing the string to the template like so: render_template('page2.html', stringval = stringval), (note also that this should be stringval_get = stringval), you can access the session object directly from templates already. So, in all, we can change your application code to:
app.py:
from flask import Flask, render_template, request, session
app = Flask(__name__)
app.secret_key = b"my_secret_key"
#app.route('/', methods=['GET', 'POST'])
def home():
if request.method == 'POST' and 'stringval' in request.form:
session["stringvalue_topass"] = request.form.get('stringval')
return render_template('page2.html')
return render_template("home.html")
#app.route('/page2', methods=['GET', 'POST'])
def page2():
return render_template('page2.html')
And your templates to:
home.html:
<!doctype html>
<h1>Enter Value </h1>
<div class="main">
<form class="pure-form" method="POST">
stringval:<br>
<input type="text" name="stringval"><br>
<button type="submit" class="pure-button pure-button-primary" value="Submit">Submit!</button>
</form>
</div>
</body>
page2.html:
<!doctype html>
<h1>You have selected </h1>
<div class="main">
{% if 'stringvalue_topass' in session %}
<pre>
{% print(session["stringvalue_topass"]) %}
</pre>
{% endif %}
</div>
</body>

Related

Flask Templating Language Not Displaying Properly

My flask template is not displaying properly. For some reason, the templating language is being displayed on the webpage.
Here is what it looks like (red circles indicate items that should not be on the web page)
I am not sure why this is happening. The templates are stored in a folder called static and in my app.py, I have the following line as well:
app = Flask(__name__, template_folder='static')
Edit: Here is the code that renders the following portion of this page:
`
{% if passphrase %}
<div>
<h4>Information</h4>
<p>Address: 123_easy_uncover_street</p>
</div>
{% else %}
<div class="col">
<h4>Enter passphrase</h4>
<form action="" method="POST" style="text-align:left">
<label for="passphrase">Passphrase</label>
<input type="text" id="passphrase" name="passphrase">
<br>
<input type="submit" value="Submit">
</form>
</div>
<div id="status" class="col" >
<p><i>Please enter your passphrase</i></p>
</div>
{% endif %}
</div>`
Flask code:
from app.bank_database import BankDatabase
from flask import Flask, request, render_template
import random
import json
app = Flask(__name__, template_folder='static')
db = BankDatabase()
#app.route('/', methods=['GET', 'POST'])
#app.route('/index.html', methods=['GET', 'POST'])
def index():
return render_template("index.html", passphrase="")
#app.route('/check_passphrase', methods=['GET', 'POST'])
def check_passphrase():
passphrase = request.args.get("passphrase")
if db.check_passphrase(passphrase):
#Show address here
#TODO - change view to show passphrase
return render_template("index.html", passphrase=passphrase)
return render_template("index.html", passphrase="")
app.run(debug=True,host="0.0.0.0")

Executing python script with flask, from button

I'm trying to execute a def/python script from flask, when clicked on button... but can't seem to figure it out.
Here's my Python Code
from flask import Flask, redirect, url_for, render_template, request
import webbrowser
app = Flask(__name__)
#app.route("/")
def home():
return render_template("index.html")
def contact():
if "open" in request.form:
print("Test")
elif "close" in request.form:
print("Test 2")
return render_template('contact.html')
if __name__ == "__main__":
app.run(debug=True)
And here is my HTML Code
<html>
<head>
<title>Home page</title>
</head>
<body>
{% extends "base.html" %}
{% block title %}Home Page{% endblock %}
{% block content %}
<h1>Test</h1>
<input type="submit" name="open" value="Open">
<input type="submit" name="close" value="Close">
{% endblock %}
</body>
</html> ```
I don't know what is in {% block content %} but you need to have a form in order to call backend where you provide the url route that you want to call and the method you want to use (usually with forms it's POST). Also in the /contact endpoint you need to provide #app.route('/contact') and that it would accept POST request #app.route('/contact', methods=['POST']). Modify your python and HTML to look like this:
from flask import Flask, redirect, url_for, render_template, request, jsonify
import webbrowser
app = Flask(__name__)
#app.route("/")
def home():
return render_template("index.html")
#app.route('/contact', methods=['POST'])
def contact():
result = False
if "open" in request.form:
result = activate_lamp() # expecting True as a result of function
elif "close" in request.form:
result = deactivate_lamp()
return jsonify({'result': result}) # expecting True as a result of function
if __name__ == "__main__":
app.run(debug=True)
<html>
<head>
<title>Home page</title>
</head>
<body>
<h1>Test</h1>
<form action="{{ url_for('contact') }}" method="post">
<input type="submit" name="open" value="Open">
<input type="submit" name="close" value="Close">
</form>
</body>
</html>
The jsonify will return an object to the front end with default 200 response code. Then you can either do something with it or ignore it. The idea is that in the route you can call other functions, but you must return a valid HTTP response to the front-end, e.g. jsonify, or plain return '', 200 might be enough.

Flask raising 405 error when submitting a form

I have just started to learn flask but I am stuck with this 405 error
# Weather App using Flask
## imports
import main
from flask import Flask
from flask import render_template
from flask import request
app = Flask(__name__)
## initalisation
#app.route('/')
def main_page(methods=["GET", "POST"]):
if request.method == "POST":
city = request.form("city")
print(city)
return render_template("main.html")
if __name__ == "__main__":
app.run(debug=True)
the main.html is
{% extends "base.html" %}
{% block content %}
<form method="POST">
<p><input type="text" name="city"></p>
<p><input type="submit" value="Submit"></p>
</form>
{% endblock %}
the POST is in the methods argument, but I cannot pinpoint where the error is
thanks in advance
Instead of having the methods list in the view function's parameters, you should have it in the brackets that follow your decorator, like so:
#app.route('/',methods=["GET","POST"])
def main_page():
# your view function
This will allow this route to be accessed through both GET and POST requests.

Why does html POST take me to an unexpected page?

I have a simple web application built with Python using flask that has three pages: main, index, and post. I am trying to get to the "if request.method == "POST"" section of the index page. To test this I've asked it to render the post.html page. For some reason when I send a POST method from the index page I'm instead being redirected to my main_page. The python code looks like this:
from flask import Flask, redirect, render_template, request, url_for
app = Flask(__name__)
app.config["DEBUG"] = True
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("main_page.html")
#implied ELSE here (if it's not GET, do the following for a POST)
return redirect(url_for('index'))
#app.route('/index', methods=['GET', 'POST'])
def new_index():
if request.method == "POST":
#I AM TRYING TO GET HERE
return render_template('post.html')
if request.method == "GET":
return render_template('index.html',)
#app.route('/post')
def post():
return render_template('post.html')
The POST method from index.html comes from this:
<div class="row">
<form role="form" method='POST' action='.'>
<textarea class="form-control" name="contents" placeholder="Enter a comment"></textarea>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
I'm not particularly familiar with HTML but I've tried everything I can think of. Any advice?
When you want to link to the same page in a form action you should actually put a question mark, an empty string, a hash or just leave out the attribute all together. Doing either of these will fix your code.
<form role="form" method='POST' action='?'>
<form role="form" method='POST' action='#'>
<form role="form" method='POST' action=''>
<form role="form" method='POST'>
My personal preference is using.
<form role="form" method='POST' action='#'>
This will validate in XHTML and doesn't open up any known attack vectors.
First thing I did was testing your API using Postman, and that all works fine: GET goes to the GET handler, POST goes to the POST handler.
The error I found is in the html form, in particular the action tag: you should point that to the API handler explicitly, and relative to the hostname. So, for example, setting that to:
<form role="form" method='POST' action='/index'>
will actually perform a POST on the /index API of your Flask app.

value error if cookie value is a string but not if an int

In my make_session function, if the passwords from the forms don't match some credentials, then it returns a string which ends up being stored as a cookie named session. In my index file, I have it set so on index.html, if the cookie value is {}, it asks for login information. If I change what is returned from the make_session function by replacing "invalid" with any integer, the code works as expected.
A bad solution to my problem is to add
except:
data = {}
before the return to my get_saved_data function setting data equal to {} but this ends up with the same results as if I had no cookie in my browser at all, but it gets rid of my error which is here: https://gist.github.com/anonymous/e101aa46f154a075b038
I suspect that the get_saved_data function may be a fault.
Map of my directory:
|---- layout.html
|---- index.html
|--- templates -|
Project -|
|--- test.py
test.py:
from flask import Flask, render_template, redirect, url_for, request, make_response
import json
def get_saved_data(key):
try:
data = json.loads(request.cookies.get(key))
except TypeError:
data = {}
return data
def make_session(form_data):
if form_data.get('username') == "username" and form_data.get('password') == "password":
return "12345"
else:
return "invalid"
app = Flask(__name__)
#app.route('/')
def index():
data = get_saved_data("session")
return render_template('index.html', saves=data)
#app.route('/login', methods=['POST'])
def login():
response = make_response(redirect(url_for('index')))
response.set_cookie("session", make_session(dict(request.form.items())))
return response
app.run(debug=True, host='0.0.0.0', port=8000)
index.html:
{% extends "layout.html" %}
{% block content %}
{% if saves == {}: %}
<p>Please log in.</p>
{% else: %}
<p>Your Session value is: {{ saves }}</p>
{% endif %}
{% if saves == {}: %}
<form action="{{ url_for('login') }}" method="POST">
<p>We take your private information very seriously. All data is encrypted not once but twice! in ROT13 to provide the best security.</p><br />
<label for="username">Please enter your username:</label>
<input type="text" name="username" /><br />
<label for="password">Please enter your password:</label>
<input type="text" name="password" /><br />
<button class="btn">Log In</button>
</form>
{% endif %}
{% endblock %}
layout.html:
<!DOCTYPE html>
<html>
<head>
<title>Character Generator</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Change your get_saved_data to the following will make any difference?
def get_saved_data(key):
data = json.loads(request.cookies.get(key, '{}'))
return data
return '{}' if there is no such key, make sure json won't complain anything.
While I haven't found a way to directly fix the issue, and using lord63.j's answer saved me a few lines of code, a way to indirectly fix the issue is to save the cookie value as a dictionary by modifying the login function to this:
#app.route('/login', methods=['POST'])
def login():
response = make_response(redirect(url_for('index')))
response.set_cookie("data", json.dumps({"session": make_session(dict(request.form.items()))}))
return response
from them on, in order to access the session value I'll need to use
saves.get('session')
as saves is equivalent to
json.loads(request.cookies.get('data', '{}'))
in the index function
#app.route('/')
def index():
data = get_saved_data("data")
return render_template('index.html', saves=data)

Categories