python flask render_template html did not render correctly - python

I'm building a python flask app implementing user log in , after user log in succefully, it will redirect to userHome.html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Python Flask Bucket List App</title>
    <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
 
    <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">
    <link href="../static/css/signup.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="header">
            <nav>
                <ul class="nav nav-pills pull-right">
                    <li role="presentation" class="active">Logout
                    </li>
                </ul>
            </nav>
            <h3 class="text-muted">Python Flask App</h3>
        </div>
 
        <div class="jumbotron">
            <h1>Welcome Home !!</h1>  
        </div> 
        <footer class="footer">
            <p>© Company 2015</p>
        </footer>  
    </div>
</body>
</html>
and the python code to perform return render_template('userHome.html')
in validateLogin :
#app.route('/validateLogin',methods=['POST'])
def validateLogin():
cursor = None
try:
_username = request.form['inputName']
_password = request.form['inputPassword']
# connect to mysql
conn = mysql.connect()
cursor = conn.cursor()
cursor.callproc('sp_validateLogin',(_username,_password))
data = cursor.fetchall()
if len(data) > 0:
return render_template('userHome.html')
else:
return render_template('error.html', error = "Wrong Username or
Password")
except Exception as e:
return render_template('error.html',error = str(e))
finally:
if cursor:
cursor.close()
conn.close()
and the signin.js :
$(function(){
$('#btnSignIn').click( function(){
$.ajax({
url: '/validateLogin',
data: $('form').serialize(),
type: "POST",
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
});
});
and finally the signin.html:
!DOCTYPE html>
<html lang="en">
<head>
<title>Sign In</title>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">
<link href="../static/signup.css" rel="stylesheet">
<script src="/static/js/jquery-3.1.1.js"></script>
<!--<script src="/static/js/jquery-3.1.1.min.map"></script>-->
<script src="/static/js/signin.js"></script>
</head>
<body>
<div class="container">
<div class="header">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation" >Home</li>
<li role="presentation" class="active">Sign In</li>
<li role="presentation">Sign Up</li>
</ul>
</nav>
<h2 class="text-muted">Release Control System</h2>
</div>
<div class="jumbotron">
<h1>Log In</h1>
<form class="form-signin">
<label for="inputName" class="sr-only">Name</label>
<input type="name" name="inputName" id="inputName" class="form-control" placeholder="Name" required autofocus>
<!--<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>-->
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required>
<button id="btnSignIn" class="btn btn-lg btn-primary btn-block" type="button">Sign in</button>
</form>
</div>
<footer class="footer">
<p>Copyright 2017 Foxconn CABG © All Rights Reserved.</p>
</footer>
</div>
</body>
</html>
but when I log in successfully it does not direct to the userHome.html page, it showed all html entities instead. Meaning the templates are working but the browser is treating wrongly.
I've tried many tricks like:
headers = {'Content-Type': 'text/html'}
return make_response(render_template('userHome.html'),200,headers)
but it still returns html entities, not html page.
This has confused me for days, thanks in advance.

Since I don't know how to send a redirect request to ajax and execute it. I will simply share the way I do things.
# Python Code
#app.route('/login')
def login():
# check if user is not logged in then render the login form
if user_not_logged_in():
return render_template('login_form.html')
# if user logged in, then redirect to userHome
else:
return redirect(url_for('userHome'))
from flask import jsonify
#app.route('/validateLogin', methods=['POST'])
def validateLogin():
# do some stuff and check for validation
if stuff_goes_well:
return jsonify({'data': 'success'})
else:
return jsonify({'data': 'failure'})
#app.route('/userHome')
def userHome():
# check if user is logged in
if logged_in_user_session_exists():
return render_template('userHome.html')
else:
# user is not logged in so redirect him to the login page
return redirect(url_for('login'))
# jQuery code
$.ajax({
url: "/validateLogin",
type: "POST",
dataType: "json",
data: data_here,
success: function(response){
if(response.data == 'success'){
# success was sent so the user logged in successfully, redirect to user home
window.location.replace('/userHome');
}else{
# there was an error in the logging in
alert('there was an error!');
}
}
});
To sum it up in a few words: simply send your data with ajax to Python. then let Python handle verification and the analysis of the data. then if all goes well, tell jQuery " hey it's all cool here " ( which is represented by the 'success' string we send ). if something was wrong then we tell jQuery that we had a problem hence the 'failure' string we send. then in jQuery we act upon the string that was sent. if it was success, then we redirect the user to the desired URL ( which is /userHome in this case ). if failure was sent then we say there was an error.
Please notice that these python checks are important so the user just doesn't type "/userHome" in the URL and be able to just view the page while he is not logged in.
I hope you find this useful.

Related

How to send a password to a Flask app when using Docker/Kubernetes?

Background:
I know this is a very basic question, but I don't have experience in Frontend apps. I recently tried sending a GET request from a static HTML page to an app running in Docker on a cloud server, and it didn't work. So now instead of an HTML page, I'm trying a Flask app that does authentication.
What I want to do:
Create an index page, where if the user is logged in, they are shown some products. If the user is not logged in, they are shown a login form to type their email id and password.
The Flask app will be deployed in Docker and be available via Kubernetes Ingress, on a Kubernetes cloud cluster. My main worry is about how the username and password will find its way from the client-side browser to the correct service. Is it done via a POST generated at the HTML page itself? Won't the POST request have to point to some specific URL? Should hashing the password be done by some JQuery script when the Login button is clicked?
What I'm unable to figure out:
Even after seeing a lot of examples, I'm unable to figure out the right way to hash and send a password to the Flash app, when the user types their email and password and clicks the "Login" button. Then if the user is logged in, it has to render an HTML page with the products shown.
If there's a simple way to do it without flask-httpauth (install with pip install flask-httpauth) or if there's a library that has cleaner syntax, that technique is also welcome.
Flask Code:
#!flask/bin/python
from flask import Flask, jsonify, abort, request, make_response, url_for
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__, static_url_path = "")
auth = HTTPBasicAuth()
#app.route('/')
#auth.login_required
def welcome():
return render_template('index.html')
#app.route('/logout')
def welcome():
return render_template('logout.html')
#auth.error_handler
def unauthorized():
return '<!DOCTYPE html><html><body><div style="text-align: center;">Unauthorized access</div></body></html>'
#app.errorhandler(400)
def not_found(error):
return '<!DOCTYPE html><html><body><div style="text-align: center;">Bad request</div></body></html>'
#app.errorhandler(404)
def not_found(error):
return '<!DOCTYPE html><html><body><div style="text-align: center;">Page not found</div></body></html>'
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0")
Login page: index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vacation Finder</title>
<!--Import materialize.css-->
<link type="text/css" rel="stylesheet" href="materialize.min.css"/>
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div>
<nav>
<div class="nav-wrapper grey darken-4">
<div style="text-align: center; font-size: 30px; font-weight: bold;">Some page</div>
<div class="row">
<div class="col s12 m8 l4 offset-m2 offset-l4">
<br>
<br>
<div class="card">
<div class="card-content">
<div class="row">
<div class="input-field col s12">
<input id="email" type="email" class="validate">
<label for="email">Email</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input id="password" type="password" class="validate">
<label for="password">Password</label>
</div>
</div>
<button id="login" class="waves-effect waves-light btn blue darken-1" style="width:100%;">Login</button>
<br>
</div>
</div>
</div>
</div>
</div>
</nav>
</div>
</body>
</html>
You can use the JWT token if you want
https://geekflare.com/securing-flask-api-with-jwt/
#app.route('/login', methods=['GET', 'POST'])
def login_user():
auth = request.authorization
if not auth or not auth.username or not auth.password:
return make_response('could not verify', 401, {'WWW.Authentication': 'Basic realm: "login required"'})
user = Users.query.filter_by(name=auth.username).first()
if check_password_hash(user.password, auth.password):
token = jwt.encode({'public_id': user.public_id, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes=30)}, app.config['SECRET_KEY'])
return jsonify({'token' : token.decode('UTF-8')})
return make_response('could not verify', 401, {'WWW.Authentication': 'Basic realm: "login required"'})
apart of this you can also check official bookinfo app istio example : You can also check this example : https://github.com/istio/istio/tree/master/samples/bookinfo/src/productpage
JWT : https://medium.com/#apcelent/json-web-token-tutorial-with-example-in-python-df7dda73b579
https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/
https://realpython.com/token-based-authentication-with-flask/

In flask, paragraph is overwriting again but I want to print them separately

Snippet of HTML:
<div class="split left" >
<div class="centered">
<div class="container">
<p>Hi!</p>
</div>
<div class="darker">
<p>{{message}}</p>
</div>
<form action="{{ url_for('index')}}" method="post">
<input type="text" name="client" placeholder="Enter Message" class="text" id="message">
<button class="glow-on-hover">Send</button>
</form>
Snippet of FLASK code:
#app.route("/")
def start():
return render_template("index.html")
#app.route("/", methods=["POST"])
def index():
message = request.form.get("client")
return render_template("index.html", message=message)
Whenever I enter value and press send button it overwrites but I want to print a new paragraph each time I press send button. The list can not be useful in my opinion because it is something like a chat app. So the list will only display one recipient's message. Any effective and easy way???
here I have recreated your code and it seems working fine. Usually, the form refreshes the current page which leads to overwriting of contents.
Python Code:
#app.route("/")
def start():
return render_template("index.html")
#app.route("/message")
def index():
message = request.args.get("msg")
return message
HTML Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function textGen(){
$.get('/message', {"msg": document.getElementById('message').value }).done(function(data){
document.getElementById("text").innerHTML += `<p>${data}</p>`;
})
}
</script>
</head>
<body>
<div class="split left">
<div class="centered">
<div class="container">
<p>Hi!</p>
</div>
<div class="darker" id="text">
</div>
<input type="text" name="client" placeholder="Enter Message" class="text" id="message">
<button class="glow-on-hover" onclick="textGen()">Send</button>
</body>
</html>
In both the components, I have created msg handler in flask and msg sender in javascript using jquery. So this solution will work in your scenario. Take a look and please write to me if you face any errors or difficulties in making this code work. And I'm not using the form so it will prevent overwriting.

Why is my POST not working after getting values

So I am getting user input from a template that uses css and jQuery, then I'm posting that data back supposedly on click. However, I am not able to access the data as I believe it is not being posted back.
I believe my ajax code is not recognizing the click, can someone please help me out. I spent the whole day trying to figure out what am I doing wrong.
#This is main code
from bottle import run, route, request, template, static_file, post
def main():
#This is main code
#route('/assets/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root='./Gui/assets')
#route('/')
def home():
return template('indexTest')
#post('/home')
def home():
radius=request.forms['radius']
noTr=request.forms['noOdTurbines']
result=radius+noTr
return ({'result': result})
if __name__ == '__main__':
main()
run(host='localhost', port=8080, debug=True)
this is jQuery code
<!DOCTYPE html>
<html>
<head>
<title>AJAX Example</title>
<script type="text/javascript">
$(document).ready(function(){
$('form').on('submit',(function(event){
$.ajax({
type: "POST",
url: "/home"
data: {
radius: $('#radius').val(),
noOfTurbines: $('#noOfTurbines').val()
},
error:function(){
alert('Error: something is wrong with values!!')
}
})
event.preventDefault();
});
}));
</script>
</head>
<body>
<form method="POST" action="/home">
<div id="exampleAccount" role="tabpanel">
<div id="exampleAccountForm">
</div>
<div>
<label for="radius">Radius of Swept-Area of Wind turbine:
</label>
<input type="text" id="radius" required>
</div>
<div >
<label for="noOfTurbines">Number of Wind turbines: </label>
<input type="text" id="noOfTurbines" required>
</div>
</div>
</div>
<div >
<button type="submit" class="btn btn-default"
id="submit">Finish</button>
</div>
</form>
</body>
</html>
I have problems with the request.forms type of multidict, so I convert to dict and this solves all my problems. I usually merge the post and string URL objects into one just to make it more flexible.
def merge_dicts(*args):
result = {}
for dictionary in args:
result.update(dictionary)
return result
payload = merge_dicts(dict(request.forms), dict(request.query.decode()))
Just remember, that bottle uses the name not the id of the form element in a post. So make sure all inputs have a name.
(Which I do not see in your example)

Inserting data into an Oracle database from a form in Python Flask

I have a Python code.
import cx_Oracle
import re
from flask import Flask, render_template, request, url_for, redirect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'd369342136ecd032f8b4a930b6bb2e0e'
#app.route('/add')
def edited():
connect = cx_Oracle.connect("********", "********", "******/XE")
cursor = connect.cursor()
cod_ed = request.form['cod_ed']
nome_ed = request.form['nome_ed']
endereco = request.form['endereco']
telefone = request.form['telefone']
cidade = request.form['cidade']
execute = """INSERT INTO editor VALUES
(:cod_ed, :nome_ed, :endereco, :telefone, :cidade)"""
cursor.execute(execute, {'cod_ed':cod_ed, 'nome_ed':nome_ed, 'endereco':endereco, 'telefone':telefone, 'cidade':cidade})
connect.commit()
#app.route('/', methods=['GET', 'POST'])
def add_data():
return render_template('forms.html')
#app.route('/post_data', methods=['GET','POST'])
def post_data():
return redirect(url_for('edited'))
if __name__ == "__main__":
app.run(host = 'localhost', port = 8000, debug=True)
And its html correspondante:
<!DOCTYPE html>
<html>
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous">
</script>
<title>Base de dados</title>
</head>
<body>
<form methods="POST" action="/post_data">
<div class="col-lg-2">
<div class="form-group">
<label for="element-1" >Codigo:</label>
<input id="cod_ed" name="cod_ed" type="text" class="form-control" placeholder="Codigo"/>
<label for="element-2" >Nome:</label>
<input id="nome_ed" name="nome_ed" type="text" class="form-control" placeholder="Nome"/>
<label for="element-3" >Endereço:</label>
<input id="endereco" name="endereco" type="text" class="form-control" placeholder="Endereço"/>
<label for="element-4" >Telefone:</label>
<input id="telefone" name="telefone" type="text" class="form-control" placeholder="Telefone"/>
<label for="element-5" >Cidade:</label>
<input id="cidade" name="cidade" type="text" class="form control" placeholder="Cidade"/>
<input class="btn btn-info" type="submit" value="Enter">
</div>
</div>
</div>
</form>
</body>
</html>
I'm relatively new to Flask and Python in general. When I run the forms, they get displayed, but when I try to insert them into the database, I get this:
werkzeug.exceptions.HTTPException.wrap.<locals>.newcls: 400 Bad Request: KeyError: 'cod_ed'
What exactly is causing it and how do I fix it?
When posting to /post_data endpoint the browser recieves a redirection code, and then gets /add without posting any data, provoking a key error.
You are fetching form elements at the wrong place. You should do the database insertion logic inside /post_data and redirect to /add afterwards.
Here you are posting the form data to /post_data and redirect it to /add so the edited function will not be able to access the request object containing the form data. So just change the form action to /add to make it work correctly.

Flask/Python 3 internal server error 500 when posting from html form

I'm new to Python & Flask and trying to set up a very basic script that takes information submitted from a form and posts it to a new page (I know, very simple right?)
I'm having limited success and can't figure out what the problem is here. It's working when I have 2 out of the 4 form fields selected in the python file:
name=request.form['name']
age=request.form['age']
This works fine and does what I expect it to do - Renders the output.html page containing 'name' & 'age'
but as soon as I try to add any more, I'm getting an internal server error (500), even through I'm copying & pasting the exact same code and only changing the variables (i.e 'number' & 'feeling') - In both the .py file and the input & output html files.
Heres the code..
Python code:
(The input form is on the /input/ page. "input_1" renders the output.html file)
from flask import Flask, render_template, request, url_for, redirect
from dbconnect import connection
from flask_debugtoolbar import DebugToolbarExtension
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'kuywergiukrewgkbyuwe'
toolbar = DebugToolbarExtension(app)
app.config.update(TEMPLATES_AUTO_RELOAD = True)
#app.route('/')
def homepage():
return render_template ("main.html")
#app.route('/input/')
def input():
return render_template ("input.html")
#app.route('/input/', methods=["POST"])
def input_1():
name=request.form['name']
age=request.form['age']
number=request.form['number']
feeling=request.form['feeling']
return render_template('output.html', name = name, age = age, number = number, feeling = feeling)
if __name__ == "__main__":
app.run()
The input.html file:
(Contains the input form)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>devserver</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="{{ url_for("static", filename="css/bootstrap.css") }}">
<link rel="shortcut icon" href="{{ url_for("static", filename="favicon.ico") }}">
</head>
<body>
<div class="container">
<div class="col">
<h2>Input form</h2>
<br>
<div class="form-group" >
<form method="post" action="{{ url_for('input') }}">
<label for="InputForm">Name</label>
<input type="text" name="name" class="form-control"/>
<label for="InputForm">Age</label>
<input type="text" name="age" class="form-control"/>
<label for="InputForm">Number</label>
<input type="text" name="number" class="form-control"/>
<label for="InputForm">Feeling</label>
<input type="text" name="feeling" class="form-control"/>
<br>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</body>
</html>
The output.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>devserver</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="{{ url_for("static", filename="css/bootstrap.css") }}">
<link rel="shortcut icon" href="{{ url_for("static", filename="favicon.ico") }}">
</head>
<body>
<div class="container">
<div class="col">
<h2>Output form</h2>
<br>
<div class="form-group" >
<form>
<h3>Output 1</h3>
<P>Your name is = {{name}}</p>
<h3>Output 2</h3>
<P>Your age is = {{age}} </p>
<h3>Output 3</h3>
<P>Your number is = {{number}}</p>
<h3>Output 4</h3>
<P>Your feeling is = {{feeling}} </p>
</form>
</div>
</div>
</div>
</body>
</html>
I cant understand why it works with only 2. When I comment out the following it works fine:
#app.route('/input/', methods=["GET","POST"])
def input():
name=request.form['name']
age=request.form['age']
#number=request.form['number']
#feeling=request.form['feeling']
return render_template('output.html', name = name, age = age) #number = number, feeling = feeling)
It's probably something quite obvious but I just can't see it.
Thanks for the help!
You usually use url_for when you have to generate urls. I would rather not complicate matter when I have to pass multiple parameters.What I would do is just this :
<form method="post" action="/input">
and in the app file :
#app.route('/input', methods=["POST"])
def input_1():
name=request.form['name']
age=request.form['age']
number=request.form['number']
feeling=request.form['feeling']
return render_template('output.html', name = name, age = age, number = number, feeling = feeling)
But if you really wanna generate urls then put the function you want to generate url for and also pass the arguments .
<form method="post" action={{url_for('input_1',name=name)}}>
and then call funtion input_1 like this:
#app.route('/input/<name>') #you can add parameters as per your wish
def input_1(name):
...
...

Categories

Resources