Gathering User Input Data in Flask - python

I am working on a flask app that will take a user input from a form and pass it on to the Todosit API to generate a task. I have been able to authenticate and verify the API version of the code is working, my only hangup now seems to be getting the data from the front end (jinja template) passed in as a variable to the Todoist API POST call.
Here is my Python code for the route:
#app.route('/', methods=['GET', 'POST'])
def home():
if request.form["submit"] == "submit":
task = request.form["task"]
due_date = request.form["dueDate"]
requests.post(
"https://api.todoist.com/rest/v1/tasks",
data=json.dumps({
"content": task,
"label_ids": [2154915513],
"due_string": due_date,
"due_lang": "en",
"priority": 1
}),
headers={
"Content-Type": "application/json",
"X-Request-Id": str(uuid.uuid4()),
"Authorization": f"Bearer {API_KEY}"
}).json()
Here is the HTML form code:
<form>
<label for="task">Enter Task:</label><br>
<input type="text" id="task" name="task"><br>
<label for="due_date">Enter Due Date (Leave Blank if None):</label><br>
<input type="text" id="due_date" name="due_date">
<input type="submit" value="Submit">
</form>
When I run this and add a task & due date, the results are not passed into the variables task & due date correctly. Does anyone have any advice on passing front end variables to the Flask route for processing? Thanks!

Add for form tag: action="{{ url_for('handle_data') }}" method="post"
And for dueDate use right key: request.form["due_date"]
Hope its help

Related

FastAPI OAuth2 Authentication Failed when data sent from HTML Form

I am using OAuth2 to store the authentication JWT access_token for employee login. The code works as intended when performing authentication through the FastAPI/docs page, but fails to do so when the username and password are sent through an HTML Login Form. In both these cases, the /token method properly receives the credentials and fetches (and returns) the access_token from the employee_login function (abstracted away and works as intended).
However, in the case of the HTML form, the oauth2 fails to store the token, and when navigating to /employees I get {"detail":"Not authenticated"}.
Would oAuth2 be the correct approach to use when HTML forms are involved or would a direct cookie-storing option be ideal? If oAuth2 can work in this manner, would you have any input on why the HTML form does not authenticate but going through the /docs page does? Thank you!
FAST API:
oAuth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
#app.get("/")
def employee_landing(request: Request, alert=None) -> dict:
'''Landing Page with auth options'''
return EMPLOYEE_TEMPLATES.TemplateResponse(
"landing.html",
{
"request": request,
"alert":alert
}
)
#app.post("/token")
async def login(request:Request, input_data: OAuth2PasswordRequestForm = Depends()):
''' Login a user '''
login_state = employee_login(input_data.username, input_data.password)
return {"access_token": login_state['token'], "token_type": "bearer"}
#app.get("/employee")
async def get_employee(token: str = Depends(oAuth2_scheme)):
''' Get employee info if logged in'''
return token
Landing Page HTML:
<!-- sign in form -->
<form action="/token" method="post">
<input type="text" name="username" placeholder="username" required>
<input type="password" name="password" placeholder="password" required>
<input type="submit" value="Sign In">
</form>

Flask - how to get HTML form input as Flask-RESTful api data

I have this form in HTML
<form action="{{ url_for('transfer-api') }}" method="post">
<p>Sender account id:</p>
<p><input type="text" name="senderId" id="senderId" minlength="20" maxlength="20"/> * 20 characters</p>
<p>Receiver account id:</p>
<p><input type="text" name="receiverId" id="receiverId" minlength="20" maxlength="20"/> * 20 characters</p>
<p>Amount:</p>
<p><input type="text" name="amount" id="amount" /> * number</p>
<input type="submit" value="transfer" />
</form>
I need to send a post request to a flask-restful api I've written
class Transfer(Resource):
def post(self):
...
return resp
api.add_resource(Transfer, "/api/transfer", endpoint="transfer-api")
If I use the flask-restful api with the requests module, it works fine
response = requests.post(BASE + "/api/transfer", json={"from": "7cdfe1555c4543558887", "to": "f30d031d5f3b49c7b2ca", "amount": 5})
print(response.json())
I want to do the same thing, but with the form input data. My class Transfer doesn't have "request.form["senderId"]" etc, but it gets the args "from", "to" and "amount" using reqparse imported from the flask-restful module.
If I run the code as it is, it gives me the message "Did not attempt to load JSON data because the request Content-Type was not 'application/json'." because I'm not giving any data to the api post request.
Have you tried this:
def post(self):
json_data = request.get_json(force=True)
[1] flask-restful (python) fails to parse post data in form-data

Redirect function not working in Python Flask

I'm sure this has a very simple solution, I have just not managed to find one anywhere on the web (that works in my case). I am trying to build a simple web app and I would like to redirect the user to a predefined #app.route() at the click of a button. I can do it indirectly by displaying a hyperlink, but would obviously much prefer if the redirection was automatic.
This is my 'Home page' >>
#app.route("/", methods=["GET", "POST", "PUT"])
def f_page():
if request.method == "POST":
# print(request.form["action"])
if request.form["action"] == "Officers":
# print(request.form["action"])
return redirect("/in2")
if request.form["action"] == "Companies":
return redirect("/in3")
return '''
<html>
<body>
<p>What do you wish to seed the network with?</p>
<form method="post" action="/">
<p><input type="submit" name="action" value="Officers" /></p>
<p><input type="submit" name="action" value="Companies" /></p>
</form>
</body>
</html>
'''
Note : The commented out 'print(request.form["action"])' was simply included to verify that my code was in fact reaching that point (which it was)
And my '/in2' & '/in3' function is >>
#app.route("/in2", methods=["GET", "POST", "PUT"])
def in2():
return("Hello")
#app.route("/in3", methods=["GET", "POST", "PUT"])
def in3():
return("Hello")
After clicking either button I would expect to see a page load with the words 'Hello', but instead my homepage is loaded and '27.0.0.1 - - [27/Jul/2021 15:47:33] "POST / HTTP/1.1" 302 -' is displayed in my terminal.
I am aware I can change the page that gets loaded by altering the route in the form action '<form method="post" action="/">' but this complicates things further down the line. I was hoping to find a solution using a similar method to that detailed above.
Any help is much appreciated!!!

How execute a function contained inside a route on form submit?

I have a form. When I submit my form, I want to execute some functions in the route that processes the form data.
Form
<form action="{{ url_for('background_process') }}" method="POST">
<input type="text" id="name" name="name" required />
<input type="url" id="url" name="url"/>
<input type ="text" id="mdp-demo" name= "mdp-demo"/>
<input type=text size=5 name=proglang>
<a href=# id=process_input><button class='btn btn-default'>Submit</button></a>
</form>
Javascript to post form data to route that processes data.
$(function() {
$('a#process_input').bind('click', function() {
$.getJSON('/background_process', {
proglang: $('input[name="proglang"]').val(),
url: $('input[name="url"]').val(),
title: $('input[name="name"]').val(),
dates: $('input[name="mdp-demo"]').val(),
}, function(data) {
$("#result").text(data.result);
});
return false;
});
Route that processes the form data.
#app.route('/background_process', methods=['GET','POST'])
def background_process():
try:
create_table()
data_entry()
url = request.args.get('url', 0, type=str)
title = request.args.get('title', 0, type=str)
dates = request.args.get('dates', 0, type=str)
if url.lower() == 'https://www.reddit.com/':
return jsonify(result='You are wise')
else:
return jsonify(result='Try again.')
except Exception as e:
return str(e)
I want to execute the create_table() and data_entry() functions when the submit button on the form is clicked.
The result at the moment is that nothing happens. These functions work when executed on app run time outside of a route. It's when they are within a route they don't work. Any suggestions as to what I should do to achieve execution of these functions inside my route?

Deleting rows from database with python flask?

I am using a flask framework, and can't seem to delete rows from the database. The code below gives a 405 error: "The method is not allowed for the requested URL." Any ideas?
In the py:
#app.route('/delete/<postID>', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries WHERE id = ?', [postID])
flash('Entry was deleted')
return redirect(url_for('show_entries', post=post))
In the html:
<h3>delete</h3>
Clicking <a href...>delete</a> will issue a GET request, and your delete_entry method only responds to POST.
You need to either 1. replace the link with a form & submit button or 2. have the link submit a hidden form with JavaScript.
Here's how to do 1:
<form action="/delete/{{ entry.id }}" method="post">
<input type="submit" value="Delete />
</form>
Here's how to do 2 (with jQuery):
$(document).ready(function() {
$("a.delete").click(function() {
var form = $('<form action="/delete/' + this.dataset.id + '" method="post"></form>');
form.submit();
});
});
...
Delete
One thing you should not do is make your delete_entry method respond to GET. GETs are meant to be idempotent (are safe to run repeatedly and don't perform destructive actions). Here's a question with some more details.
Alternatively, change POST to DELETE to get you going.
#app.route('/delete/<postID>', methods=['DELETE'])
Ideally, you should use HTTP DELETE method.
I used flaskr as a base for my Flask project (as it looks like you did as well).
In the .py:
#app.route('/delete', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries where id = ?', [request.form['entry_id']])
g.db.commit()
flash('Entry deleted')
return redirect(url_for('show_entries'))
In the HTML:
<form action="{{ url_for('delete_entry') }}" method=post class=delete-entry>
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="submit" value="Delete" />
</form>
I wanted a button, but you could easily use a link with the solution here.
A simple <a href= link in HTML submits a GET request, but your route allows only PUT requests.
<a> does not support PUT requests.
You have to submit the request with a form and/or with JavaScript code.
(See Make a link use POST instead of GET.)

Categories

Resources