User input from python flask to be sent to ansible variable - python

Say I have an example flask app which basically is a small webform that would take in user input data called applet.py.(The code is taken from a online blog that shows an example flask app build).
from flask import Flask,render_template,request
app = Flask(__name__)
#app.route('/form')
def form():
return render_template('form.html')
#app.route('/data/', methods = ['POST', 'GET'])
def data():
if request.method == 'GET':
return f"The URL /data is accessed directly. Try going to '/form' to submit form"
if request.method == 'POST':
form_data = request.form
return render_template('data.html',form_data = form_data)
app.run(host='localhost', port=5000)
The input is captured in this below form.
<form action="/data" method = "POST">
<p>Name <input type = "text" name = "Name" /></p>
<p>City <input type = "text" name = "City" /></p>
<p>Country <input type = "text" name = "Country" /></p>
<p><input type = "submit" value = "Submit" /></p>
</form>
If I were wanting to send this received user input into ansible variables and then trigger the ansible script to run and execute the playbook based on the given variables. How can I do that? I have googled a lot around this, couldn't find a suitable example that fits my use case. (Disclaimer, not very knowledgeable about both flask and ansible, learning as I do). Appreciate help, reference and advice.

You can use the ansible_runner module to run your playbook (docs).
import ansible_runner
#app.route('/data/', methods = ['POST', 'GET'])
def data():
if request.method == 'GET':
return f"The URL /data is accessed directly. Try going to '/form' to submit form"
if request.method == 'POST':
form_data = request.form.to_dict()
r = ansible_runner.run(playbook='test.yml', extravars=form_data)
# check ansible return code
if r.rc != 0:
abort(400, 'Ansible error')
return ('', 204)
If your playbook takes some time to run you might be better adding the job of running it to a queue and processing it separately.

Related

Having trouble sending data from html to python using flask

I have an HTML index page that sends input data to a python script which processes the data and outputs it in a 2nd HTML page. On a local host, the process works fine and the data is displayed as desired. But when I try to host the process online, I get an error saying the URL cannot be found. If it helps, I'm using Heroku.
Apologies in advance for any poor lingo. I only just started learning how to code recently.
1st HTML
<form action = "https://webaddress/result" method = "POST">
<h1> Enter info: </h1>
<input type="text" name="info">
<input type="submit" value="Submit"/>
</form>
Python:
from flask import Flask, render_template, request
from bs4 import BeautifulSoup
import requests
# https://doi.org/10.2118/21513-MS
app = Flask(__name__)
#app.route('/')
def student():
return render_template('Trial.html')
#app.route('/result.html',methods = ['POST', 'GET'])
def result():
return render_template("result.html",result = output)
if __name__ == '__main__':
app.run(debug = True)
The input in the 1st HTML would be sent to the python section to be broken down and rearranged (left out that part so the python code wouldn't be too long) before being output into result.html. This worked on a local host using http://localhost:5000/ and http://localhost:5000/result.
When I run it on Heroku, I get the error message:
Not Found
The requested URL /result was not found on this server.
Update: Problem solved.
Having some issues understanding your results() function. output isn't defined anywhere and type isn't used at all.
I believe your action parameter is incorrect.
Try:<form action="/result" method = "POST">
Here is a working version of what I hacked together for you:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET'])
def home():
return '''
<form action="/result" method = "POST">
<h1> Enter info: </h1>
<input type="text" name="info">
<input type="submit" value="Submit"/>
</form>
'''
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
type = ''
if 'info' in request.form:
result = request.form['info']
return result
if __name__ == '__main__':
app.run(debug=True, port=8888, host='0.0.0.0')
Your form refers to /result (no .html extension), but your route is for /result.html (with the extension). Try removing the .html from your route:
#app.route('/result', methods=['POST', 'GET'])
def result():
return render_template("result.html", result=output)

Writing html form input to text file using python

I'm trying to use this code to print a number from a html form to a text document for storage but it doesn't seem to be working
#app.route("/result",methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
timer = request.form['timer_input']
f = open("timer.txt", "w")
f.write("Water every {} days".format(timer)
templateData = template(text = "timer")
return render_template('timer.html', **templateData)
<form>Set frequencys (e.g. 2 = every 2 days): <br>
<input type ="number" name="timer_input">
<br>
</form>
does anyone know why it's not working? I've looked at several places for alternatives but they all use cgi or php and I'm not interested in using either
Even though your initial problem looks solved, here are several bits of suggestions:
It is more typical for one address (view) to display a form and another
address to showswhat the result is when form is completed.
File write operation looks more secure as a separate function. You need to close the file, or better use with.
You do nothing on GET, so the function can be simplified.
Here is the code with these ideas in mind:
from flask import Flask, request, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('timer.html')
#app.route("/result", methods= ['POST'])
def result():
timer = request.form['timer_input']
log_message = "Water every {} days".format(timer)
screen_message = "Sure, will water every {} days!".format(timer)
save(log_message)
return screen_message
def save(text, filepath='timer.txt'):
with open("timer.txt", "w") as f:
f.write(text)
app.run()
templates/timer.html:
<html><body>
<form action = "result" method = "POST">
Set frequencies (e.g. 2 = every 2 days):
<br>
<input type ="number" name="timer_input">
<input type = "submit">
<br>
</form>
</body></html>

Use flask to receive data from form

I am trying to use flask to get data from a html form. The form shows up on the website ok, but when I submit python doesn't receive it.
Html code:
<form action="/signup" method="post">
<input type="text" name="email"></input>
<input type="submit" value="signup"></input>
</form>
Python code:
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
#app.route('/about/')
def about():
return render_template('about.html')
#app.route('/signup', methods = ['POST'])
def signup():
email = request.form['email']
print("The email address is '" + email + "'")
return redirect('/')
if __name__ == '__main__':
app.run(debug=True)
APP
--static
----main.css
--templates
----html code(home.html)
python code(hello.py)
The code works fine for me.
The only thing I would change is using the url_for() construct instead of directly specifying your endpoints.
I.E.: use return redirect(url_for('home'))
Alternatively, try to provide a GET request for your 'signup' endpoint.
Add 'GET' to your methods argument
Put your printing block under an if statement (if request.method == "POST")
Underneath this block put something to return. (return redirect(url_for('home')), return render_template('xyz.html'), etc.)

Flask request.form not retrieving any data

I'm posting data to the following Flask view using an HTML form. For some reason, the server is never created. I've confirmed that the create_server method works from the interpreter. Another form I'm using to log in works. Why isn't this working?
#app.route('/add-server/', methods=['GET', 'POST'])
def add_server_view():
if request.method == 'post':
server_name = request.form['server_name']
create_server(server_name)
return redirect(url_for('index')
return render_template('add_server.html')
<form method=post>
<input name=server_name>
</form>
request.method will be in all caps and the comparison is case sensitive.
if request.method == 'POST':
This code in Werkzueg forces the method name to uppercase for consistency.

Problems redirecting to dynamic URLs in Flask with 'action'

My app has a text box and a submission button. I am trying to create and redirect to dynamic URLs in my app, that are based off of what is typed in the text box. For example, the user enters in '1234', clicks submit, then is taken to 'website.com/results/1234'. The problem seems to be that the HTML for my button doesn't want to redirect the user to the new, dynamic URL. I am passing this to the HTML with Jinja.
Here is what I have.
The user starts on the home page, that is defined like this
#app.route("/home/", methods=["GET", "POST"])
def start():
return render_template("dashboard.html")
Dashboard.html has a text box and submission button (below). As you can see, the action of this button is to redirect to {{ results_page }}, where "results_page" comes from my Python function load_results (also below) and is passed to the HTML with render_template.
<div>
<form action="{{ results_page }}" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
</div>
The results page of my app uses the user input to look up some information and display it.
#app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'POST':
query = form.pmid.data #This is the user input
results_page = "website.com/results/"+query
return(query)
#do lots of stuff using the query
return render_template('results.html', form=form, results_page = results_page)
except Exception as e:
return(str(e))
If I run my app like this, the home page is fine, but when I click "Submit", the app doesn't take in the user input or do anything with it. Simply the home page refreshes.
I am new to web development, but since this code works fine if I hardcode the button to action = "website.com/results" in the HTML, AND do without the <query> in /results/<query> for the results page, I think that only a few adjustments should be needed to make my app dynamically redirect to and load pages correctly. Right now, I'm not sure what I'm missing. Please let me know where I'm going stray.
EDIT -
Now I have implemented a handle_form function that redirects to my dynamic URL. This function properly redirects but then I get a 404 error.
#app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect('/results/'+query)
I have also edited my form in the HTML action to go to /form/
<form action="website.com/form/" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" placeholder="18952863, 18269575" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
With this, my site will properly redirect to /results/<query>/ (e.g. /results/1234) but I get a 404 error. Here is how I have changed my load_results
#app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data #THIS IS THE USER INPUT FROM THE FORM #referencing 'class pmidForm'
return query
.
.
#do stuff
I think I am very close but need to figure out why I am getting a 404 error. My guess is that I am using "GET" incorrectly. My form in the HTML uses method="post". Since this does not match with "GET", is there no way for my load_results(query) function to retrieve the contents of the form?
EDIT 2 -
Changed handle_form to redirect with url_for:
#app.route('/form/', methods=["POST"]) #handles form submission
def handle_form():
form = pmidForm(secret_key='super secret key')
if request.method == "POST":
query = request.form['pmid']
return redirect(url_for('.load_results', query=query))
And changed load_results to not return "query"
#app.route('/results/<query>', methods=["GET"])
def load_results(query):
form = pmidForm(secret_key='super secret key')
try:
if request.method == 'GET':
query = form.pmid.data # This shouldn't work??
.
.
# do stuff with the variable "query"
With this, it's still returning the 404 Error as before. Should I not be using if request.method == GET ?
Edit 3 -
Even a very simplified load_results will give me the 404 error, so I'm not sure what's up.
#app.route('/results/<query>', methods=["GET", "POST"])
def load_results(query):
q = query
return render_template('test.html', q=q)
EDIT - 3
It seems that the accepted solution IS the correct solution to this problem, however there is an issue with uwsgi in my server that is re-directing it to the wrong location :(
Your punctual problem is that /home route function also needs to put the results_page url on the templating context.
results_page = "website.com/results"
return render_template("dashboard.html", results_page=results_page)
Since the variable is undefined, flask is calling the original endpoint on the form submission.
Your larger problem is that your appraoch isn't going to get you a dynamic results url that looks like /results/1234.
Typical approaches are to redirect on the server side when you handle the post request; or to use JavaScript in the client to get the form data and change the browser location to /results/1234.
A simplified version of how to handle this with a server side redirect might look something like this. One route that handles the form submission and another that displays results. You simply redirect from one to the other to get the nice url.
#app.route('/form', methods=["POST"])
def handle_form():
query = form.pmid.data #This is the user input
return redirect(url_for('.load_results', query=query))
#app.route('/results/<query>') *removed the method spec to handle the redirect?
def load_results(query):
.
.
# do something with query

Categories

Resources