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.
Related
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
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.
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.
So I am serving a index.html file from Flask.
The index.html file comes from a built project using: https://github.com/facebookincubator/create-react-app
I have a couple routes setup in the React app, for example:
"/users"
and "/contracts"
When I refresh one of these routes, I get a 404 from flask, but while "clicking" on links found on the site, they work perfectly fine.
When you are clicking the links in the interface, React is re-rendering the page without any server-side intervention, and then updating the route in the URL bar. When loading however, you are making that route request to the server direct, and Flask does not have that route registered.
Simplest way is to register these routes in the decorator for the function serving your homepage view
#app.route('/')
#app.route('/users')
#app.route('/contracts')
def home_page():
If there are many many routes, you may want to use the catch-all URL pattern.
Specifying every route is too prone to error. Here is a more general solution.
Add an error handler to catch 404:
#app.errorhandler(404)
def handle_404(e):
if request.method == 'GET':
return redirect(f'/?request_path={quote_plus(request.path)}')
return e
The error handler will redirect to the home page, where your React works, passing the actual requested request_path as a parameter.
In your view handler do this:
#app.route('/')
def public_page_index(request_path=None):
return render_template('index.html',
request_path=request.args.get('request_path', ''))
The index.html template will create a hidden input:
<input type="hidden" name="request_path" value="{{request_path}}">
Then the actual React path will be available for your React code to respond to. This is what I've done in my Home page component, using jquery and useHistory().
useEffect(() => {
// find if server refresh needs history
const $request_path = $('input[name=request_path]');
const val = $request_path.val();
if (val) {
$request_path.val("");
history.push(val);
return;
}
}, []);
I am having an issue with my fading modal routing in flask. My user login opens a modal and i m trying to implement the POST feature from the modal in flask.
I thought of implementing under index and search for the form name form the the post like below.
#app.route('/')
#app.route('/index')
def index():
if request.form.get('login', None) == 'submit' :
return 'Yeah hooo'
return render_template('index.html')
However, when i execute the code above, i get
Method Not Allowed
on /index. My other worries is that my Login form is in the template and can therefore be call from any routes. Since template is not a route. Please is there any way i can achieve this in flask ? Or do i have to take the login in to a seperate html file instead of the template ?
You should explicitly add POST to the list of methods that can be processed
#app.route('/', methods=['GET', 'POST'])
See here for more information
As per the second question, it's ok as long as your login form makes POST request to the same route ('/' in your case).