Prevent duplicate form submissions while awaiting a response Flask Python - python

I am running a large request via API and massaging some data before the user sees it. I am looking to prevent the user from clicking the download button while all this information is processed. What would be the best way to accomplish this through a Flask Form?
Here is my HTML:
<form method="POST">
<button type="submit" name="download" value="download" class="button is-primary is-light">Download</button>
{% if error_statement %}
<article class="message is-danger">
<div class="message-body">
{{ error_statement }}
</div>
</article>
{% endif %}
</form>
Here is my Flask Form:
from datetime import date
import pandas as pd
from flask_wtf import FlaskForm
from wtforms import *
from flask import (
Flask,
g,
redirect,
render_template,
request,
session,
url_for,
flash,
Response
)
app = Flask(__name__)
app.secret_key = 'secret'
#app.route('/home', methods=["POST", "GET"])
def home():
class MyForm(FlaskForm):
submit = SubmitField('Download')
if request.method == 'POST':
form = MyForm()
if request.form['download'] == 'download':
#At this point I have code where I call a bunch of APIs and convert data to a CSV file
#This process takes anywhere between 1-3 minutes to complete
if not final_df.empty:
today = date.today()
return Response(final_df.to_csv(index=False, header=True), mimetype="text/csv", headers={"Content-disposition": "attachment; filename=export" + today.strftime("%Y/%m/%d") + ".csv"})
else:
error_statement = 'Something Went Wrong Please Try Again'
return render_template("login.html", error_statement=error_statement)
return render_template('home.html', form=form)
return redirect(url_for('login'))
Can anyone provide guidance on how to prevent the user from clicking the download button while my data is processed?

Related

How to keep same page in Flask

this is a very simple code with Flask. Every time I click submit I go to another page and I lose my input field and my button.
I wonder HOW I can keep the same page and have just a refresh of the page when I have the output. Or if there is any other solution. Thank you
from flask import Flask, render_template_string, request
app = Flask(__name__)
html = """
<div class="form">
<form action="{{url_for('sent')}}" method="POST">
<input title="Title" placeholder="Enter something" type="text" name="line" required> <br>
<button class="go-button" type="submit"> Submit </button>
</form>
</div>
"""
#app.route("/")
def index():
return render_template_string(html)
#app.route("/", methods=['GET', 'POST'])
def sent():
line = None
if request.method == 'POST':
line = request.form['line']
return line
if __name__ == "__main__":
app.run(debug=True)
You can redirect back to the original page after processing the input
Instead of
return line
You can
from flask import redirect, url_for
return redirect(url_for("index"))

How to send data in Flask to another page?

I'm using Flask to make a tickets booking app. But for now I'm little confused on how to send data from one page to another page, like this snippet of code:
#app.route('/index', methods = ['GET', 'POST'])
def index():
if request.method == 'GET':
date = request.form['date']
return redirect(url_for('main.booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
return render_template('main/booking.html')
The date variable is a request from a form, and for now I want to send the date data to booking function. What is term for that purpose..?
Passing data is possible for get request from one route to another.
You are almost there to get the submitted date value in booking route.
app.py:
from flask import Flask, render_template, request, jsonify, url_for, redirect
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
def index():
if request.method == 'POST':
date = request.form.get('date')
return redirect(url_for('booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
date = request.args.get('date', None)
return render_template('main/booking.html', date=date)
if __name__ == '__main__':
app.run(debug=True)
main/index.html:
<html>
<head></head>
<body>
<h3>Home page</h3>
<form action="/" method="post">
<label for="date">Date: </label>
<input type="date" id="date" name="date">
<input type="submit" value="Submit">
</form>
</body>
</html>
main/booking.html:
<html>
<head></head>
<body>
<h3>Booking page</h3>
<p>
Seleted date: {{ date }}
</p>
</body>
</html>
Output:
Home route with a form to submit the date
Getting the date in booking route
Disadvantages:
The values (e.g.: date) are passed as URL parameters from one route to another.
Anyone with a get request can access the second part (e.g. booking route).
Alternatives:
Use session storage as #VillageMonkey suggested.
Use Ajax to facilitate multi part forms.
You can also use flask session to send data from one page to another page.
from flask import Flask, render_template, request, jsonify, url_for, redirect,
session
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
def index():
if request.method == 'POST':
date = request.form.get('date')
session["date"] = date
return redirect(url_for('booking', date=date))
return render_template('main/index.html')
#app.route('/booking')
def booking():
date = session.get("date")
return render_template('main/booking.html', date=date)
if __name__ == '__main__':
app.run(debug=True)

Validate that a WTForms BooleanField is checked

I am creating a form using Flask-WTForms.
I am using a BooleanField so that a user can indicate they agree terms.
I cannot validate the BooleanField upon submission to ensure that it has been checked. I have tried using Required(), DataRequired() and custom validation but in each case I have not received a validation error.
Here are the nuts and bolts of the application:
from flask import Flask, render_template, session, redirect, url_for, flash
from flask_wtf import Form
from wtforms import BooleanField, SubmitField
from wtforms.validators import Required, DataRequired
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'impossibletoknow'
bootstrap = Bootstrap(app)
class AgreeForm(Form):
agreement = BooleanField('I agree.', validators=[DataRequired()])
submit = SubmitField('Submit')
#app.route('/', methods=['GET', 'POST'])
def index():
form = AgreeForm()
if form.validate_on_submit():
agreement = form.agreement.data
if agreement is True:
flash('You agreed!')
return redirect(url_for('index', form=form))
form.agreement.data = None
agreement = False
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
And here is the index.html template...
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
Any suggestions would be gratefully received.
Works for me— you do need to use DataRequired() (Required is being deprecated):
from flask import Flask, render_template
from flask_wtf import Form
from wtforms import BooleanField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.secret_key = 'STACKOVERFLOW'
class ExampleForm(Form):
checkbox = BooleanField('Agree?', validators=[DataRequired(), ])
#app.route('/', methods=['post', 'get'])
def home():
form = ExampleForm()
if form.validate_on_submit():
return str(form.checkbox.data)
else:
return render_template('example.html', form=form)
if __name__ == '__main__':
app.run(debug=True, port=5060)
Template:
<form method="post">
{{ form.hidden_tag() }}
{{ form.checkbox() }}
<button type="submit">Go!</button>
</form>
<h1>Form Errors</h1>
{{ form.errors }}
You do not have to include DataRequired() in your form, because it does not make sense, being a boolean. You must take of the incoming form data in the post method by saying if true.

Python Flask Save Form Data to DB

I am new to Flask and I am trying to save form data from a Flask form to database using SQLAlchemy and I am not having any luck. I have tried several methods from research I found both here and outside of this forum.
When I take the simplistic route, the web form works and I can enter data but it will not populate the DB.
----Models----
class QIDMapping(db.Model):
id = db.Column(db.Integer, primary_key=True)
qid_number = db.Column(db.Integer)
br_field_name = db.Column(db.String(75))
vendor_field = db.Column(db.String(75))
----Forms----
class QIDForm(Form):
qidnumber = IntegerField('qidnumber', validators=[DataRequired()])
brfieldname = StringField('brfieldname', validators=[DataRequired()])
vendorfieldname = StringField('vendorfieldname')
----Views----
from flask import render_template, flash, redirect, session, url_for,
request, g
from flask_wtf import form
from app import app, db
from .forms import QIDForm
from .models import User, QIDMapping
from flask.ext.sqlalchemy import SQLAlchemy
#app.route('/qidmapping', methods=['GET', 'POST'])
def qid_map_update():
form = QIDForm()
return render_template('qidmapping.html',
title='QID Mapping',
form=form)
----qidmapping.html----
{% block content %}
<h1>Map QIDs to Vendor File</h1>
<form action="" method="POST">
{{form.hidden_tag()}}
<p>
Please enter the QID, BrassRing Field Name and Vendor Tag
<br>
<h2>QID Number {{ form.qidnumber(size=25) }}<br></h2>
<h2>BR Field {{ form.brfieldname(size=25) }}<br></h2>
<h2>Vendor Field {{ form.vendorfieldname(size=25) }}<br></h2>
</p>
<p><br>
</p>
<p><input type="submit" value="Save Fields">
</p>
</form>
{% endblock %}
I have also tried the method in this post Flask - WTForm - save form to db
and when I do, I get a Method Not Allowed error and I'm not sure why.
----view for question 20837209 format----
#app.route('/qidmapping', methods=['GET', 'POST'])
def qid_map_update():
form = QIDForm()
if form.validate_on_submit():
newform = (
form.qidnumber.data,
form.brfieldname.data,
form.vendorfieldname.data
)
db.session.add(newform)
db.session.commit()
return redirect('/qidmapping')
return render_template('qidmapping.html',
title='QID Mapping',
form=form)
Any help would be greatly appreciated!
Try replacing
newform = (
form.qidnumber.data,
form.brfieldname.data,
form.vendorfieldname.data
)
db.session.add(newform)
with
m = QIDMapping()
m.qid_number = form.qidnumber.data
m.br_field_name = form.brfieldname.data
m.vendor_field = form.vendorfieldname.data
db.session.add(m)
... and if that doesn't work. Do your standard POST troubleshooting:
1) Verify POST request
2) Ensure CSRF is working correctly.
3) Log validation errors / success
4) Check for DB exceptions

Determine which WTForms button was pressed in a Flask view

I have a page with multiple links to redirect the user to different pages. I thought using a form would be nicer, so I defined a WTForms Form with multiple SubmitFields. How do I determine which button was clicked and redirect based on that?
class MainForm(Form):
user_stats = SubmitField('User Stats')
room_stats = SubmitField('Room Stats')
#main.route('/')
#login_required
def index():
form = MainForm()
return render_template('index.html', form=form)
<form action="#" method="post">
{{ wtf.quick_form(form) }}
</form>
You added two buttons to the form, so check which of the fields' data is True.
from flask import Flask, render_template, redirect, url_for
from flask_wtf import Form
from wtforms import SubmitField
app = Flask(__name__)
app.secret_key = 'davidism'
class StatsForm(Form):
user_stats = SubmitField()
room_stats = SubmitField()
#app.route('/stats', methods=['GET', 'POST'])
def stats():
form = StatsForm()
if form.validate_on_submit():
if form.user_stats.data:
return redirect(url_for('user_stats'))
elif form.room_stats.data:
return redirect(url_for('room_stats'))
return render_template('stats.html', form=form)
app.run(debug=True)
<form method="post">
{{ form.hidden_tag() }}
{{ form.user_stats }}
{{ form.room_stats }}
</form>

Categories

Resources