Flask button passing variable back to python - python

I've found a lot of into similar to this, but I just can't quite make it work. Basically, I've got a button, and upon pressing it, I want to fire that value back to my flask backend.
HTML Button:
<form action="" method="POST" ><button class="btn btn-danger" type="submit" name="delete" value="{{ item2 }}"><span class="glyphicon glyphicon-trash"></span> Delete</button> </form>
Python:
#app.route('/', methods=["GET","POST"])
def home():
if request.method == 'POST':
if request.form['delete'] == post_id:
(my sql login/cursor stuff....)
sql = "DELETE FROM test_table WHERE post_id = ?"
c.execute(sql, (post_id,))
return redirect("/")
As you can see, I'm populating the links (and subsequent variable) with jinja. It populated the button as it should, but sending it back to my python script isn't working.
UPDATE:
When I run this, I get an internal server error. I cannot see what the routing error is because I can't get debug to work (using wsgi/werkzeug).
I think we can conclusively say is that by not defining post id is why it's not working. So my question is, when the button sends data BACK to python, what value (and how) does python grab? is it name= or value= or something else?

Your problem is
request.form['delete'] == post_id
You get value from button (request.form['delete']) and try to compare with value in variable post_id which doesn't exists.
If you want to get value from button and assign to variable post_id then you need
post_id = request.form['delete']
or
post_id = request.form.get('delete')
and then you can use post_id in SQL query.
#app.route('/', methods=["GET","POST"])
def home():
if request.method == 'POST':
post_id = request.form.get('delete')
if post_id is not None:
(my sql login/cursor stuff....)
sql = "DELETE FROM test_table WHERE post_id = ?"
c.execute(sql, (post_id,))
return redirect("/")

Related

html/flask file to query postgres

I'm hoping someone can help me, i am a complete beginner with Flask and Postgres.
Basically, I created a python file, that takes user input to query the existing postgres database, this works perfectly. However, now I want to create a flask web app to do the exact same.
Accept the user will input the name on the html text box, and once the user hits submit, it needs to query the Postgresql database and return the requested columns for that specific row, exactly like the db_test.py file does.
Below is my python file that works and give me the expected results, but when I tried to create the app.py file with the html file, I am not able to get it to work, and I'm sure I'm missing something simple, but I don't know what.
This is the db_connect.py file that works - now I want to create the same results using flask and html.
# This is the db_test.py file which works as expected.
import psycopg2
# This section will try to create a Database Connection
try:
db_connection = psycopg2.connect(
host="localhost",
database="my_db",
user="postgres",
password="password",
port=5432
)
# This section will test Database Connection and return an exception if the connection fails.
print("Connected to server successfully")
except psycopg2.DatabaseError as Error:
print(f"Connection failed to server {Error}")
# This is the user input for that will be used to query the database table.
name = input("What is the name? ").title()
# This is the cursor for querying the Database table for the name that the user input and prints out the title, name and email
cursor.execute(
"SELECT id, name, email FROM details WHERE name = %s", (name,))
details = cursor.fetchall()
for d in details:
print(d)
# This Cursor closes the database connection and an If Statement to check and confirm that the database connection is closed.
cursor.close()
# This closes the connection to the Database
if db_connection:
db_connection.close()
print("Disconnected from server")
This is the second part of the project, with flask and html, but I can't get it to work.
This is the app.py file:
import creds
from flask import Flask, request, render_template
from flask_sqlalchemy import SQLAlchemy
# initialising the app
app = Flask(__name__)
app.config['SECRET_KEY'] = f"{creds.thisisasecret}"
# This is the Database URI
app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://{creds.username}:{creds.password}#localhost:5432/{creds.database}"
app.config['SQLALCHEMY_TRACK_MODIFICATION'] = True
db = SQLAlchemy(app)
class Details(db.Model):
__tablename__ = 'details'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(length=50))
email = db.Column(db.String(length=30))
#app.route("/")
def show_details():
return render_template("index.html", details=details.query.all())
app.run(debug=True, host="127.0.0.1", port=3000)
And this is the index.html file which also displays the text box with a submit button, but when i enter the name, nothing happens.
<body>
<div>
DB Search
</div>
<div>
<form action="{{url_for('show_details')}}" method="GET">
<input type="text" name="title" placeholder="Name">
<button type="submit">Submit</button>
</form>
</div>
<hr/>
</body>
I have re-written the app.py and html file, I believe it's a lack of knowledge but all the research I'm doing online is not helping me fix this problem.
Basically when I type the name in the text box on the html page and click on submit, it should return the id, name and email on the html page.
Can someone please point me in the right direction?
Generally, to process form input with Flask, you'd define the form as below:
<form method="POST">
then, to process it in Flask:
#app.route("/", methods=["GET", "POST"])
def show_details():
if request.method == "POST":
form_data = request.form
name_entered_in_form = form_data["title"] # Access form field by `name=` parameter
new_details = ... # populate data based on name entered
return render_template("index.html", details=new_details)
return render_template("index.html", details=details.query.all())
this code provides details about all fields in the database by default, and when a name is passed in and submitted, it passes in just those details to the exact same page. Note how the same app route ("/") is able to handle both types of requests - GET requests for displaying data and POST requests for handling submitted data.

Flask_wtf - validate_on_submit() error on page load

Flask_wtf's validate_on_submit() is never True on visiting the page for the first time, so it always flashes the else part's (code below) Error message which is always an empty dict.
But the form validation and submission are working properly - the success flash message can be seen on a valid post. And the Error flash doesn't disappear after a valid submission.
Reproducible code:
# necessary import stmts & other stuff
class MyForm(FlaskForm):
sub = StringField(validators=[DataRequired("Choose the title")])
body = TextAreaField(validators=[DataRequired(),Length(min=20)])
subm = SubmitField('Submit')
app.config['SECRET_KEY'] = 'my key'
#app.route('/', methods=['GET','POST'])
def index():
fo = MyForm()
flash('Submitted:'+str(fo.is_submitted())) # False on first time visit
#flash('After Validate:'+str(fo.validate()))
if fo.validate_on_submit():
ex = mytable(bodys = fo.body.data, subs = fo.sub.data)
# DB session add & commit stmt here
flash('Submitted','success')
return redirect(url_for('index'))
else:
flash('After val Errors:'+str(fo.errors))
return render_template('index.html',form=fo)
If I un-comment fo.validate()...it flashes csrf_token': ['The CSRF token is missing.'] and the other data required error msgs but as shown below the html template has form.hidden_tag(). Also used {{ form.csrf_token }} instead of hidden_tag()...no success.
<form method="POST" action="">
{{ form.hidden_tag() }}
{{ form.sub }}
{{ form.body }}
{{ form.subm }}
</form>
Please help to get rid of the validation error on page load, Thank you
So on initial get you don't need to validate your form because there's no data yet, only do it when it's actually posted, like so:
if request.method == 'POST':
if fo.validate_on_submit():
# DB session add & commit stmt here
flash('Submitted', 'success')
return redirect(url_for('index'))
else:
flash('After val Errors:' + str(fo.errors))

WTForm used in two different views validate only using one view

I'm having a problem using a WTForm in two different views. One view creates a new item, using the form data. The other view display information for items already in the database and the user should be able to update the form data from there.
I can create and view the items in the database. The problem is updating the information when in in the display view. The steps I take are something like:
Create a item in /create. Before saving to database check that the same ID is not already in database. If exists show a flash and do not permit saving the item. Reloading /create
To display information about a existing item the route /display/<item> call the database, populate the form and show the information using the same form.
Desired behavior
To update information when in /display/<item>. After updating any field data and pressing the submit button, the form should save to the database and reload /display/<item>.
Actual behavior
After pressing the submit button the form takes me back to the /create route, and performs the ID validation.
I don't understand why, being in a different view /display/<item>, the form's submit button takes me to the /create view.
The code goes something like this:
This is a simple form
class ItemForm(FlaskForm):
id = IntegerField("id", validators=[DataRequired()])
name = StringField("Email", validators=[DataRequired()])
submit = SubmitField("Submit")
With this I create a new item in the database, checking that the same Id is not already in the database:
#app.route("/create", methods=["GET", "POST"])
def create():
form = ItemForm()
if form.validate_on_submit():
item = item = Item.query.filter(Item.id == form.id).first()
# Check the same id is not already created
if item is not None:
flash('item already in database')
return redirect(url_for("create"))
item = Item()
form.populate_obj(item)
db.session.add(item)
db.session.commit()
return redirect(url_for("display", item = form.id))
else:
return render_template("create.html", form=form)
And then after there is created items in the database i can call a display route. In this route I should be able to update the fields in the form and save it to the database. Whit out validating as the the same ID is already present in the database (I'm updating, no creating a new one).
#app.route("/display/<item>", methods=["GET", "POST"])
def display(item):
item = Item.query.filter(Item.id == item).first()
form = ItemForm(obj=item)
if form.validate_on_submit():
form.populate_obj(item)
db.session.add(item)
db.session.commit()
return redirect(url_for("display", item=form.id))
else:
return render_template("display.html", form=form)
The problem is that when in the /display/<item> route, the submit button takes me back to the /create route. Performing the validations in there. Of course the item is already created in the database so I get the flash and I'm redirected to /create, when it should reload /display/<item>.
Could someone point me in the right direction, please. Thank you all!
My mistake, but #the_gañañufla asked the right question. The problems of coding alone.
I had added an action to the HTML and i forgot to remove it.
I had
<form id="form_item" action="{{ url_for('create') }}" class="form" method=post>
After correct it I have:
<form id="form_product" action="" class="form" method=post>

Python Flask - Store input values into variables then print it

I am trying to get users amount of coins saved to my flask project. So users are supposed to write in a input field how much coins they want to display, for instance "1200", then I want flask to receive that and print it on my table I have. I have done some research, and also tried copy a bit of code from my "contact" form, but no luck at all!
Here is my HTML code:
div class="search_div">
<form action="GET">
<input type="text" class="coins-box" placeholder="Amount of Coins" />
</form>
</div>
Here is my python code:
#app.route('/bflipper', methods=['GET', 'POST'])
def bFlipper():
if request.method == 'GET':
userInput = request.form['input']
return render_template('flipper.html', userInput=userInput)
I mainly want it to be stored into a variable on python, as I need to add some other stuff with that user input later on!
Make a global variable and assign value to it inside the function
my_value = ""
#app.route('/bflipper', methods=['GET', 'POST'])
def bFlipper():
if request.method == 'GET':
global my_value
my_value = request.form['input']

Flask putting form into URL

I've been working on a form that sends data to a scraper and simultaneously generates a URL from form input. The returned templates works flawlessly, but the URL change ends up giving me the entire form in the URL and I can't figure out why.
The URL ends up looking like this:
http://localhost/options/%3Cinput%20id%3D%22symbol%22%20name%3D%22symbol%22%20type%3D%22text%22%20value%3D%22%22%3E
I'd like it to look like this:
http://localhost/options/ABC
Form class:
class OptionsForm(Form):
symbol = StringField('Enter a ticker symbol:', validators=[Required(), Length(min=1, max=5)])
submit = SubmitField('Get Options Quotes')
Views:
# Where the form data ends up
#app.route('/options/<symbol>', methods=['GET', 'POST'])
def options(symbol):
# Created this try/except so I could test functionality - for example, I can do 'localhost/options/ABC' and it works
try:
symbol = request.form['symbol']
except:
pass
return render_template('options.html', symbol=symbol, company_data=OS.pull_data(symbol, name=True))
# Where the form lives
#app.route('/', methods=['GET', 'POST'])
def index():
form = OptionsForm()
print(form.errors)
if form.validate_on_submit():
return redirect(url_for('options', symbol=form.symbol.data))
return render_template('index.html', options_form=form)
Template:
<div id="options_div">
<form method="POST" name="symbol_form" action="{{ url_for('options', symbol=options_form.symbol) }}">
{{ options_form.hidden_tag() }}
{{ options_form.symbol(size=10) }}
{{ options_form.submit(size=10) }}
</form>
Any help would be appreciated.
Try adding enctype='multipart/form-data' to the form tag. It looks like your form is using application/x-www-form-urlencoded, the default.
Edit OK so check this out. When your template is being rendered there is no value in that data attribute (In the url_for call). When not referencing the data attribute (as your original question shows), you're referencing the actual form element (which is why you see all of that html being passed in the url). Here are your options (that I see):
Use some kind of frontend javascript to bind the form's action attribute to the value in the input box. Something like angular would help for this (but is overkill if you don't use any of its other features).
Just have the form POST to /options (no symbol in url). Then, grab the symbol attribute from the form data.

Categories