Flask background processing after render template - python

I'm trying to submit a form, where the user can potentially upload several files, from which a background process is triggered that will take several minutes to complete. The issue I have currently is that when the user clicks the Submit button, nothing appears to happen for the user for several seconds while the files upload. Is there a way I can redirect to a (static*) holding page while the files upload and the processing happens, and then once the background process completes, this renders a new template?
Using Python 3.6.1 and Flask 0.12.2.
* I say static for now, but at some point in the future, I wish to use AJAX to update this page to give more information to the user
N.B. I have seen several similar questions, and the general answer is to use a module like Celery to perform async operations. Unfortunately, I do not have access to Celery as I cannot download new packages due to corporate policy.
main.py:
from flask import Flask, request, render_template, url_for, redirect
app = Flask(__name__, static_url_path = "/static", static_folder = "static")
#app.route("/", methods=['GET'])
def home():
return render_template("index.html")
#app.route("/in_progress", methods=['GET', 'POST'])
def in_progress():
if request.method == 'GET':
# Do the background processing here
return render_template('result.html') # This is the final part of the process
elif request.method == 'POST':
# Upload the files and do some pre-processing with the form
# This takes a couple of seconds so appears to not be doing anything for the user
# Want to render the GET 'in_progress.html' template at the top of this to give a better user experience
return render_template('in_progress.html') # Reloads same page using GET
index.html:
...some irrelevant HTML
<form action="{{ url_for('in_progress') }}" method="POST" id="form" name="form" enctype="multipart/form-data">
...other irrelevant HTML

Related

If I have two routes in flask pointing towards the same url, how does flask decide what functions to run?

I have a simple flask app where I take an image file path from an input page and then switches over to an output page with the image being displayed. My app works properly and manages to access my saved files and displays them on the new page, but I realized I have two routes that point towards the same place. My code is shown below:
#app.route('/')
def main_page():
return render_template('input_receiver.html')
#app.route('/', methods = ['POST', 'GET'])
def get_input():
if request.method == 'POST':
user = request.form['nm']
return redirect(url_for('success', name=user))
These two functions point towards my initial localhost:5000 page, the first function renders an html file with a text field input and a button. In order to connect to the actual flask script, it includes the following line in the form tag:
<form action = "http://localhost:5000" method = "post">
('nm' is the text field input on the initial HTML page)
The second function takes in the user input of the local image file path and redirects them to an HTML file after they press a button which displays the picture they entered. This is done through the below function.
#app.route('/<name>')
def success(name):
return render_template('popup.html', picture_path = "/static/" + name)
Both routes point towards the initial localhost:5000 page, so how does flask handle execution? If this is considered as a bad way to create this sort of functionality, what is the better way of doing it?
You can put both GET and POST in the same method under same route.
#app.route('/', methods = ['POST', 'GET'])
def get_input():
if request.method == 'POST':
user = request.form['nm']
return redirect(url_for('success', name=user))
return render_template('input_receiver.html')
You have already given the methods as GET and POST for the route / - method get_input(), so you can completely remove the other method - main_page.
Both your GET and POST request can be handled by this one method.

werkzeug.routing.BuildError with Flask -- trying to build a very simple webapp

I'm trying to develop a simple webapp that prompts the user for their address, requests forecast information from the NWS through their API, and prints out the results, but I'm running into some issues tying together the HTML and the Python script. I'm still new to programming in general and this is all a very rough copy at the moment, here's the relevant code:
weather.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def home():
return render_template('weather.html')
#app.route('/forecast', methods=['GET', 'POST'])
def forecast():
if request.method == 'POST':
location = request.form['address']
# gets the weather information
return render_template('forecast.html', varying_forecast = forecast, wfo = wfo_info)
if __name__ == '__main__':
app.run(debug=True)
weather.html:
<form action="{{ url_for('forecast') }}" method="post">
Enter your address here: <input type="text" name="address"><br>
<input type="submit" name="submit" value="Get My Forecast!"><br>
</form>
When I try to go to 127.0.0.1:5000 I receive this error: "werkzeug.routing.BuildError: Could not build url for endpoint 'forecast'. Did you mean 'home' instead?" To the best of my knowledge this error occurs when url_for fails to find a route, but given that the forecast function does exist I'm confused where the error is coming from. Even after commenting out the form tag in the HTML the error persists. I tried getting rid of the "wfo" and "varying_forecast" in the return statement but that also didn't do anything. The only way to fix it is by setting the url_for of the action of the form to home, but I don't see any way to run the code in there and return the forecast information, considering it's already returning the home page. I'm having trouble understanding why it fails to display the weather.html page as written.

Implementing File Uploads From Angular to Flask

I am trying to implement file uploading for my Web tool. The front end is developed using angular and the back end is using flask. Following tutorials on the flask website I have set up the following flask app:
from flask import Flask, request
from werkzeug import secure_filename
import os
UPLOAD_FOLDER = '/home/openstack/Documents/Confmrg/bcknd/uploads'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route('/uploader' , methods = ['GET' , 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return 'File Uploaded'
if __name__ == '__main__':
app.run(debug = True)
I run this and the web server is hosted on http://localhost:5000
So on my angular component html I place the following:
<form action="http://localhost:5000/uploader" method="POST" enctype = "multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
</form>
However when I run the angular web page, and test it by uploading a file and clicking submit, nothing happens. There is no error, and nothing is output in the console. I must be missing something, could someone point me in the right direction?
Form onSubmit handler
To answer your immediate question, what's happening is input type submit in Angular calls the onSubmit method of the form (instead of submitting the form like in plain HTML). And because you don't have a handler for onSubmit in your class, nothing is happening.
For a quick test, follow this link to create a simple onSubmit handler method to test that your submit button works.
Here's a Stackblitz example which logs to console when you click the submit button: https://stackblitz.com/edit/angular-uy481f
File upload
To make file upload work, you would need to make a few things. This touches the component class, creating a new service and injecting it, and updating your form to bind it to the class.
Create a proper Angular form. Here's an example.
Create a method that will handle the onSubmit() of the form.
Create a service that will handle Http calls to upload files.
Inject the service into your class, and call the file upload method of that class.
As you can see, there's a lot involved in making this work unlike having a simple post form in the template. As such, it will be too much for a single answer.
But hopefully, the initial paragraph answered your question and the rest of the answer pointed you in the right direction.

Send data to html page through python

I have a python-flask app. And my source.py :
from flask import Flask, flash, redirect, render_template, request, session, abort
import os
from Modules.registry_bend.DockerImageReceiver import http_requester_v2_catalog, read_configurations
app = Flask(__name__)
#app.route('/v1')
def display_index():
return render_template('index.html')
if __name__ == "__main__":
# http_requester_v2_catalog("192.168.1.7", 5000)
app.secret_key = os.urandom(12)
app.run(debug=True, host='0.0.0.0', port=3150)
I run this source.py, and then open the browser and hit localhost:5000/v1.Then index.html appears. So, the challenge is, that a few seconds later I get some data, and I want to add them to index.html. How could it be possible? I have already called index.html once.
You can send the dynamic data to your HTML by sending context variables through the render template method.
flask.render_template(template_name_or_list, **context)
Renders a template from the template folder with the given context.
Parameters:
template_name_or_list – the name of the template to be rendered, or an iterable with template names the first one existing will be rendered
context – the variables that should be available in the context of the template.
Example -
return render_template('index.html', variable1=random.random(), variable2=random.random())
And in your HTML code you need to include these flask variables.
Example -
<p> {{variable1}} </p>
<p> {{variable2}} </p>
And whenever you refresh you html page in your browser. The new data will be displayed.

Flask redirects to wrong view when redirecting to index

I keep running into this strange issue that I can't seem to figure out a solution for. I cannot copy and show all of my code in it's entirety here, but I will try to outline the general structure of my flask app to present my issue.
(Let's ignore all of the content in the /static folder and my helper modules)
I have 3 main views, let's call them viewA, viewB, and index:
viewA.html
viewB.html
index.html
viewA and viewB both display two forms, but with different content (i.e. viewA displays form1 & form2, and viewB also displays form1 & form2).
A simplified version of my script code is as follows:
#imports
from flask import Flask, render_template, session, redirect, url_for, request
from flask_wtf import FlaskForm
#etc. etc.
app = Flask(__name__)
app.config['SECRET_KEY'] = 'blah blah blah'
manager = Manager(app)
bootstrap = Bootstrap(app)
moment = Moment(app)
class FormOne(FlaskForm):
sample_field = StringField('Sample Field:')
class FormTwo(FlaskForm):
other_field = StringField('Other Field:', validators=[Required()])
submit = SubmitField('Submit')
class UploadToA(FlaskForm):
content= StringField('Content to send to view A:', validators=[Required()])
submit = SubmitField('Submit')
class UploadToB(FlaskForm):
content= StringField('Content to send to view A:', validators=[Required()])
submit = SubmitField('Submit')
#app.route('/ViewA', methods=['GET', 'POST'])
def view_a():
"""
A lot of data manipulation
"""
form1 = FormOne()
form2 = FormTwo()
if request.method == 'GET':
"""
populate forms with content
"""
if request.method == 'POST':
if form2.validate_on_submit();
"""
clear session variables
"""
return redirect(url_for('index'), code=302)
return render_template('viewA.html', form1=form1, form2=form2)
#app.route('/ViewB', methods=['GET', 'POST'])
def view_b():
"""
A lot of data manipulation
"""
form1 = FormOne()
form2 = FormTwo()
if request.method == 'GET':
"""
populate forms with content
"""
if request.method == 'POST':
if form2.validate_on_submit();
"""
clear session variables
"""
return redirect(url_for('index'), code=302)
return render_template('viewB.html', form1=form1, form2=form2)
#app.route('/', methods=['GET', 'POST'])
def index():
"""
Some data manipulation
"""
formA = UploadToA()
formB = UploadToB()
if formA.validate_on_submit()':
"""
pull content from form A
create some session variables
"""
return redirect(url_for('view_a'))
if formB.validate_on_submit()':
"""
pull content from form B
create some session variables
"""
return redirect(url_for('view_b'))
return render_template('index.html', formA=formA, formB=formB)
if __name__ == '__main__':
manager.run()
Now the issue at hand I am having here is that for some strange reason when I'm in 'viewA.html' and I submit my form, I SHOULD be redirected back to 'index.html' but for some strange reason it redirects me to 'viewB.html'. Furthermore, the opposite also holds true: when i'm in 'viewB.html' and I submit my form, I SHOULD also be redirected back to 'index.html' but it redirects me to 'viewA.html'. Yet, if I am in either viewA or viewB, I have no issues of going back to the index view if I manually enter the url into my browser.
Any ideas as to why I might be running into this issue?
Thanks in advance :)
I have finally figured out the source of my problem. It turns out that in my 'viewA.html' template file, I had the following in my < form > tag:
<form class="form form-horizontal" method="post" role="form" action="{{url_for('index')}}">
And the problem all lies in that last part:
action="{{url_for('index')}}"
As a result, everytime I would submit form2 in viewA.html it would create a post request for my index page rather than a post request for the viewA.html page (which caused a redirect to the wrong view). Thus, by simply removing the action attribute (action="{{url_for('index')}}"), I was able to solve my problem!
Since the full code isn't here, I can't confirm this for sure, but what I think is happening is this:
You open form A
You submit form A
It sends a redirect to /index
It sends a redirect to /FormB
if formB.validate_on_submit():
return redirect(url_for('view_b'))
This is probably sending a redirect to View B. Try changing that last line to something like return something_else and seeing if it sends that after submitting form A.

Categories

Resources