This question already has answers here:
TypeError: 'dict' object is not callable
(8 answers)
What is the cause of the Bad Request Error when submitting form in Flask application?
(1 answer)
Python dictionary increment
(7 answers)
Closed 4 years ago.
I am working on an assignment for a Flask application with a function that does different things based on the value of a hidden field in a form on the index.html page. I am to have only two routes: '/' (index.html) and '/process' (which performs actions on index.html).
When I run this in Flask (python server.py in a virtualenv), and click the button "Make Money" on index.html, I get this error:
"TypeError
TypeError: 'ImmutableMultiDict' object is not callable"
Can someone please tell me how I can get the desired value from the hidden input?
contents of server.py
import datetime
import random
from flask import Flask, render_template, redirect, request, session
app = Flask(__name__)
app.secret_key = 'fooBarBaz'
#app.route('/')
def index():
return render_template('index.html')
#app.route('/process', methods=['GET','POST'])
def process():
if request.method == 'POST':
target = request.form('name')
if target == 'clothing':
new_money = random.randrange(10, 21)
session['balance'] += new_money
timestamp = datetime.datetime.now()
session['register'] += ("Received" + new_money + " dollars at " + timestamp.strftime("%Y/%m/%d %I:%M %p"))
return render_template('index.html')
app.run(debug=True)
contents of index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div container>
<div class='balance'>
<p>Your balance: {{ session['balance'] }}</p>
</div>
<div class="shops">
<div class="clothing">
<h2>Clothing Store</h2>
<p>(earns 10 - 20 dollars)</p>
<form action="/process" method="post">
<input type="hidden" name="clothing">
<input type="submit" value="Make Money!">
</form>
</div>
</div>
<div class="register">
<h4>Receipt Tape</h4>
<p>{{ session['register'] }}</p>
</div>
</div>
</body>
</html>
The form should be something like below, with a value defined for the hidden input:
<form action="/process" method="post">
<input type="hidden" name="clothing" value="clothing">
<input type="submit" value="Make Money!">
</form>
Without changing the logic too much, the register section could accept html tags to render linebreaks
<p>{{ session['register']|safe }}</p>
Then with minimal changes, this is how you could resolve some issues you are facing in the view. To avoid error about session key not declared, the best way is to used the method get with 0, or "" instead of the None returned when the key is not found:
#app.route('/process', methods=['GET','POST'])
def process():
if request.method == 'POST':
target = request.form.get('clothing')
if target == 'clothing':
new_money = random.randrange(10, 21)
session['balance'] = session.get('balance',0) + new_money
timestamp = datetime.datetime.now()
session['register'] = "{}<br>Received {} dollars at {}".format(
session.get('register',''),
new_money,
timestamp.strftime("%Y/%m/%d %I:%M %p"))
return render_template('index.html')
Related
This question already has answers here:
Passing HTML to template using Flask/Jinja2
(7 answers)
Closed 4 months ago.
I have this code that compute the similarity between 2 strings:
import spacy
from spacy.lang.pt.examples import sentences
X ="some string 1"
Y ="some string 2"
nlp = spacy.load('pt_core_news_sm')
X_nlp = nlp(X)
Y_nlp = nlp(Y)
token_x = [token.text for token in X_nlp]
token_y = [token.text for token in Y_nlp]
print("Similarity:", X_nlp.similarity(Y_nlp))
Now I want to transform this code in an API with flask, I tried to follow a tutorial:
from flask import Flask,render_template,url_for,request
import re
import spacy
from spacy.lang.pt.examples import sentences
nlp = spacy.load('pt_core_news_sm')
app = Flask(__name__)
#app.route('/',methods=["POST"])
def process():
X_nlp = nlp(input())
Y_nlp = nlp(input())
print("Similarity:", X_nlp.similarity(Y_nlp))
if __name__ == '__main__':
app.run(debug=True)
the code above returns: "GET / HTTP/1.1" 405 -
You are trying to reach the URL "/". However, within your code there is no route defined for this path. Thus, the error 404 is returned.
You need a route that accepts both a GET and a POST request to both display a form and receive data from a submitted form sent via POST.
Otherwise, a 405 error is returned because the request method is not allowed.
#app.route('/', method=['GET', 'POST'])
def index():
if request.method == 'POST':
# Handle a POST request and the data sent here.
# ...
Within Flask it is not possible to request input with input().
As mentioned above, you need a form within an HTML page. Within this form you can define input fields that must be provided with a name attribute in order to query them on the server side.
<form method="POST">
<input type="text" name="x" />
<input type="text" name="y" />
<input type="submit">
</form>
If the submit button is now pressed, the data of the form, as defined in the method attribute, is sent to the server via POST and can be queried here. The input fields are queried using the name attribute.
Finally, the endpoint must have a return value. In your case, this is the template that displays the page with the form and outputs the possible result.
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
x = request.form.get('x', '')
y = reutest.form.get('y', '')
# ...
return render_template('index.html')
So the entire code of your application should look something like this.
Flask (app.py)
from flask import (
Flask,
render_template,
request
)
import spacy
nlp = spacy.load('pt_core_news_sm')
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# Handle a POST request and the data sent here.
x_nlp = nlp(request.form.get('x', ''))
y_nlp = nlp(request.form.get('y', ''))
resultado = x_nlp.similarity(y_nlp)
# Return a rendered template and pass defined variables to the template.
return render_template('index.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
</head>
<body>
<form method="POST">
<input type="text" name="x" />
<input type="text" name="y" />
<input type="submit">
</form>
{% if resultado -%}
<p>Similaridade: {{ resultado }}</p>
{% endif -%}
</body>
</html>
This question already has an answer here:
Django form.errors not showing up in template
(1 answer)
Closed 9 months ago.
So, I was learning Django from a tutorial and came across form validation. The tutor's version had errors pop-up on screen when validation failed but nothing shows up on my form.
Here is my forms.py.
from django import forms
from django.core import validators
def check_for_z(value):
if value[0].lower() != 'z':
raise forms.ValidationError('Name should start with z')
class FormName(forms.Form):
name = forms.CharField(validators = [check_for_z])
email =forms.EmailField()
text = forms.CharField(widget=forms.Textarea)
This is my views.py file.
from django.shortcuts import render
from myformapp import forms
def form_name_view(request):
form = forms.FormName()
if request.method == 'POST':
filled_form = forms.FormName(request.POST)
if filled_form.is_valid():
# print the form data to terminal
print("Validation success")
print('Name: ' + filled_form.cleaned_data['name'])
print('Email: ' + filled_form.cleaned_data['email'])
print('Text: ' + filled_form.cleaned_data['text'])
return render(request, 'myformapp/formpage.html', {'form' : form})
And this is my template for the page.
<!DOCTYPE html>
{% load static %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Form Page</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<div class="container">
<form method="post">
{{form.as_p}}
{% csrf_token %}
<input type="submit" class="btn btn-primary" value="Submit">
</form>
</div>
</body>
</html>
So whenever i enter a name that's not beginning with z i am supposed to get an exception on the screen but nothing shows up. My code is pretty similar to what the tutor is showing on his machine. Can someone point me in the right direction as to what i am doing wrong.
Thanks
Try using ValidationError (from django.forms import ValidationError) instead of forms.ValidationError
I have been working on a web interface using Flask and having some issues with back button in browser as after logging out hitting it takes user back inside. I have found similar questions and tried their answers but the issue is not resolved. I am attaching a simple example kindly have a look at it.
Main
from flask import Flask, request,session, redirect, url_for, render_template
from os import urandom
app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
app.secret_key = urandom(24)
#app.route('/', methods=['POST', 'GET'])
def index():
if request.method == 'POST':
session['Email id'] = request.form.get('Email Id')
Pass = request.form.get('Password')
try:
if session['Email id'] == 'KK#gmail.com' and Pass == 'KKK':
return render_template('Logged_in.html')
except:
return render_template('login.html')
return render_template('login.html')
#app.route('/sign_out')
def sign_out():
session.pop('Email id')
return redirect(url_for('index'))
#app.after_request
def add_header(r):
r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
r.headers["Pragma"] = "no-cache"
r.headers["Expires"] = "0"
r.headers['Cache-Control'] = 'public, max-age=0'
return r
if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True, threaded=True)
login.html
<!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>Document</title>
</head>
<body>
<form action="{{ url_for('index') }}" method="POST" id="login" class="input-group">
<input type="text" class="input-field" placeholder="Email Id" required name="Email Id">
<input type="text" class="input-field" placeholder="Password" required name="Password">
<button type="submit" class="submit-btn" style="color: white;">Log in</button>
</form>
</body>
</html>
Logged_in.html
<h2>You are Logged in</h2>
<i class="fas fa-sign-out-alt"></i>Log out
Your problem is that when users push the back button their browser will re-do the POST request. You need to use the POST/redirect/GET pattern to prevent this. For this you need four endpoints in totalt:
GET / : Check in the session that the user is logged in and render Logged_in.html, otherwise redirect to /login.html
GET /login.html : Render login.html
POST /sign_in : Check username and password. If successful, update the session and redirect to /
POST /sign_out : Log out the user session and redirect to /login.html
Do not render templates in your POST endpoints, just make them manipulate the session and then redirect.
value=user_id is not taking the new value defined by def login():.for e.g. if the entered user_id from HTML page is 200, 300 and 100. The values will be assigned as 0, 200, 300. That is, when home page is displayed it will be showing user 0 for entered value 200, and for second time it is showing 200 for entered value 300 and for third time it is showing 300 for entered value 100.
I need a real time values i.e. for entered value 200 home page should have value 200, and for 300 it should be 300. Could anyone please help me with this? Please advice. Thanks in advance. Note: HTML code is not optimized.
from flask import Flask, render_template # Flask is the class within the flask library
from flask import request, redirect
user_id = int(0)
app = Flask(__name__) # Instance of the object Flask. __name__: this gets value of name of python script
#app.route('/', methods=["GET", "POST"]) # login page
def login():
if request.method == "POST":
global user_id
user_id = request.form['userid']
print(user_id)
return render_template("login.html")
#app.route('/home/') # This the URL i.e. home page
def home():
return render_template("home.html", value=user_id)
if __name__ == "__main__":
app.run(debug=True)
HTML Code for Login page here.
<!DOCTYPE html>
<html>
<head>
<title>Recommender System App</title>
<link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/main.css')}}">
</head>
<body>
<header>
<div class="container">
<h1 class="logo">Movie Recommender System</h1>
<strong><nav>
<ul class="menu">
</ul>
</nav></strong>
</div>
</header>
<form action="{{ url_for('login') }}" method="post">
<div class = "Login Fields">
<b>Username:</b> <input type="number" placeholder="Numbers only" name='userid'>
<p><b>Password:</b> <input type="password" placeholder="Enter Password" name= 'password' id="pwd"></p>
<input type="submit" onclick="check(this.form)" class="button">
</div>
<p></p>
<p></p>
<div>
<p>Test User IDs:</p>
<li>224</li>
<li>216</li>
<li>681</li>
<li>19</li>
<li>82</li>
<li>305</li>
<li>44</li>
<li>268</li>
<p>Password: 123Swaroop</p>
</div>
</form>
<script language="javascript">
function check(form)/*function to check userid & password*/
{
if(form.password.value == "123Swaroop")
{
window.open(href = "{{ url_for('home') }}")
}
else
{
alert("Wrong Password or User Id")/*displays error message*/
}
}
</script>
</body>
</html>
HTML code for home page here:
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/main.css')}}">
</head>
<body>
<header>
<div class="container">
<h1 class="logo">Welcome User: {{ value }}</h1>
<strong><nav>
<ul class="menu">
</ul>
</nav></strong>
</div>
</header>
<div class = "home">
<h1>Top Rated Movies</h1>
<p>This is test website</p>
</div>
</body>
</html>
You also need to call the global value within your home() function:
from flask import Flask, render_template, request, redirect
user_id = int(0)
app = Flask(__name__)
#app.route('/', methods=["GET", "POST"])
def login():
if request.method == "POST":
global user_id
user_id = request.form['userid']
print(user_id)
return render_template("login.html")
#app.route('/home/')
def home():
global user_id
return render_template("home.html", value=user_id)
if __name__ == "__main__":
app.run(debug=True)
However, using global variables is usually considered bad practice so you could also consider something like this:
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
#app.route('/', methods=["GET", "POST"])
def login():
return render_template("login.html")
def get_user_id():
try:
if request.method == "POST":
user_id = request.form['userid']
return user_id
else:
# Handle error or do something else
except:
# Handle error or do something else
#app.route('/home/')
def home():
try:
return render_template("home.html", value=get_user_id())
except:
# Handle error or do something else
if __name__ == "__main__":
app.run(debug=True)
I am building flask app and I am trying to understand the routes , methods in flask documentation. I wrote a code which uses GET to submit the fields of a form :
#app.route('/',endpoint='buf')
def index():
page = """
<DOCTYPE! html>
<html lang="en-US">
<head>
<meta charset=utf-8">
</head>
<body>
<form action="/hello" method="GET">
First name: <input type="text" name="fname" id="fname" ><br>
Last name: <input type="text" name="lname"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
"""
return page
#app.route('/hello',endpoint="new",methods=['GET','POST'])
def index():
if request.method=='POST':
return 'Hello %s' % (request.form['fname'])
else:
return 'Hello %s' % (request.form['fname'])
I get an error when I use 'GET' instead of 'POST' in my html form tag. Is there a way I can access the fields of the form using GET instead of POST?
From the relevant section at the quickstart guide
To access parameters submitted in the URL (?key=value) you can use the args attribute:
searchword = request.args.get('key', '')