400 Bad Request Error on POST request with Flask - python

I am attempting to return data from a HTML form with a POST request using Flask. For some reason I get a 400 Bad Request error. Looking at Chrome Dev Tools, I can see that all of the form fields with the input tag are part of the post request. The select tag with the dropwdown list is not being captured and I think this is creating the error. Anyone know why the select tag is not being captured in the post request? Any help much appreciated.
Here is the HTML form:
<label for="vendor">Select Vendor</label>
<div class="flextable p-b" style="padd">
<div class="flextable-item">
<select class="selectpicker" data-live-search="true" form="addInvoice" name="vendor" id="vendor">
<option>Jack Jaffa & Associates</option>
<option>Jacobs/Doland/Beer LLC</option>
<option>Jenkins & Huntington Inc.</option>
<option>Joseph J. Blake & Associates, Inc.</option>
<option>Langan (Geotechnical)</option>
<option>Madison Realty Capital</option>
<option>McNamara Salvia, Inc</option>
<option>Metropolis Group, Inc</option>
<option>National Grid</option>
</select>
</div>
<div class="flextable-item">
<button type="button" class="btn btn-xs btn-primary-outline">Add vendor</button>
</div>
<label for="invoice_number">Invoice Number:</label>
<input type="text" class="form-control p-b" placeholder="Every vendor invoice # must be unique" name="invoice_number" id="invoice_number">
<label for="invoice_amount">Amount:</label>
<input type="text" class="form-control p-b" placeholder="$0.00" name="invoice_amount" id="invoice_amount">
<label for="invoice_amount">Description:</label>
<input type="text" class="form-control p-b" placeholder="$0.00" width="100%" name="description" id="description">
<div class="spacer"></div>
<div class="flextable">
<div class="flextable-item">
<label for="date_received">Date received:</label>
</div>
<div>
<div class="flextable-item">
<div class="input-group">
<span class="input-group-addon">
<span class="icon icon-calendar"></span>
</span>
<input type="text" value="01/01/2015" class="form-control" data-provide="datepicker" style="width: 200px;" name="date_received" id="date_received">
</div>
</div>
</div>
</div>
</div>
<div class="modal-actions p-t-lg">
<button type="button" class="btn-link modal-action" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn-link modal-action" id="submit" >
<strong>Save + Continue</strong>
</button>
</div>
</form>
Here is the Flask python route:
#app.route('/add_invoice', methods=['GET', 'POST'])
def add_invoice():
""" Method for capturing form data to add invoice items to database"""
if request.method == 'POST':
find_cost_code = 7777 # eventually need code to lookup cost-code from POST request
print request.form['invoice_number']
print request.form['invoice_amount']
print request.form['description']
print request.form['vendor']
print request.form['date_received']
return "This is a test"
ADDED INFO:
So if I remove this line, the bad request error goes away:
print request.form['vendor']
This is because the "vendor" field is the only one in the html form that uses a select tag for input and that data is not catpured in the post request dictionary (which i can see in Chrome Dev Tool). The POST request is missing the field associated with the select tag. Not sure how to capture the select tag in the form data...

I've faced this issue many time when dealing with flask form, I think the solution is to enable csrf token protection :
according to this you need to initialise and enable it for you app!
Most of time error 400 is due to missing CSRF token.
you can do it as :
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
for initialisation
and in your form add:
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
hope it will help!!
feel free to edit.

form="addInvoice"
This attribute as part of my HTML form markup was what caused the error. I'm not sure exactly why but when it is removed, the error goes away.
(Thanks for your help above in trying to look into this.)

You need getlist to capture select.

Related

Keep getting HTTP 405 Method Not Allowed error when trying to POST form data with Flask

I am trying to capture HTTP form data using Python and Flask, but I keep getting "method not allowed" error. I have been trying to figure out why for some time with no luck. Here is what my code looks like:
#app.route("/add_recipe")
def addrecipepage():
if request.method=="post":
print ("Successful post request") # Just testing if code is working so far
return render_template("add_recipe.html")
and the HTML code:
<form id="contact" action="browseAll" method="post">
<div class="row">
<div class="col-md-6">
<fieldset>
<input name="name" type="text" class="form-control" id="name" placeholder="Recipe Name..." required="">
</fieldset>
<div class="col-12">
<textarea name="demo-message" id="recipeText" placeholder="Enter Ingredients & Instructions Here" rows="15"></textarea>
</div>
<div class="col-md-12">
<button type="submit" id="form-submit" class="button">Add The Recipe!</button>
<button id="uploadPhotoButton">Upload A Photo!</button>
</div>
</form>
When I click on the submit button, I get a HTTP 405 Method Not Allowed error. Anybody have any ideas as to why after looking at this? "browseAll" is another HTML page that I created an endpoint for in my app.py file. The same error gets thrown even if I don't specify an action though.
You are doing a POST (your form has method = "post") but your route does not have a post method attached to it. When you define a route without attaching a method, it defaults to GET. You need to do this
#app.route("/add_recipe", methods =['GET', 'POST'])

Bootstrap 4 input field not sending value to server (python, flask, GAE)

I can't get an input field in a form to send a value to the server. (I'm using flask + python on Google App Engine).
Please excuse me if this is a rookie question...
Part of my html template file:
<form class="form-inline" action="/rm_list" method="POST">
<div class="row" >
<div class="col-span-6">
<fieldset>
<input class="form-control form-control-lg" type="text" name="searchtext" placeholder="Product...">
<input name="text1">
<button class="btn btn-primary" type="submit"><i class="material-icons w3-text-black" >search</i></button>
</div>
...
...
some radio buttons
So I dumped the POST data to the terminal to debug:
my_data = request.form
for key in my_data:
print ('form key '+key+" "+my_data[key])
After trying different solutions, I found that the culprit is the type="text" attribute.
I could see the value of the simple text1 input, but the value from the searchtext input just wasn't in the received data :-(
If I remove "type="text" as follows:
<input class="form-control form-control-lg" name="searchtext" Placeholder="Product...">
then the searchtext field is received Ok by the server.
Any ideas what I'm doing wrong?
Thanks!
It seems to me that your field is simply missing the value attribute. – Anonymous

Get Data from Bootstrap Modal via POST request

I need to get data from a bootstrap modal input. I'am using the following code :
#app.route('/rejets_modeles', methods=("POST","GET"))
def rejets_modeles():
{code}
if request.method == 'POST':
uname = request.form['uname']
print("----")
print(uname)
return render_template ('rejets_modeles.html', tables=[df.to_html(table_id = 'rejets_modeles')], titles=df.columns.values, header="true")
And here is my HTML code
<form action="POST">
<div class="modal-body-modifs">
<p>Gestion du rejet : </p>
<label><b>NOM</b></label>
<input type="text" name="uname"></br>
<label><b>PRENOM</b></label>
<input type="text" name="uprenom"></br>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-default" data-dismiss="modal"> OK</button>
</div>
</form>
I don't even have the ("---") printed, that means that my 'POST' request isnt' interpreted. How can I fix that ? Thank you
It has to be method instead of action
<form method="POST">
In action you can set url to which it has to send form data - ie.
<form method="POST" action="/rejets_modeles">
but if you want to send to the same url then you don't have to set it.
Solved. The problem was data-dismiss="modal" in my input tag. If you delete this the modal will close and the form will be sent via POST request.

How to transmit form-data without POST with python requests?

I'm writing a little piece of python code to login on several "Investing"-Websites of mine and get out the current amount of money invested. I'm using pythons requests library and analyze the html-source to identify the form and the fields to fill in.
So, a form may look like this:
<form class="onboarding-form" id="loginForm" action="https://estateguru.co/portal/login/authenticate" method="post" data-redirect="https://estateguru.co/portal/home">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" class="form-control main-input" name="username">
<label class="bmd-label-floating main-label">E-Mail</label>
<em id="username-error" class="error bmd-help help-block" style="display:none;">This field is required.</em>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<input type="password" class="form-control main-input login-pass" name="password">
<label class="bmd-label-floating main-label long-label">Passwort (Mindestens 8 Zeichen)</label>
<em id="password-error" class="error bmd-help help-block" style="display:none;">This field is required.</em>
<i class="zmdi zmdi-eye"></i>
</div>
</div>
</div>
In this case, my code looks like this:
import requests
_username = 'xxx'
_password = 'yyy'
loginUrl = 'https://estateguru.co/portal/login/authenticate'
readUrl = 'https://estateguru.co/portal/portfolio/overview'
with requests.session() as s:
payload = {"username": _username, "password": _password}
final = s.post(loginUrl, data = payload)
result = s.get(readUrl)
print(result)
This works like a charm for many websites! But now i got an website without the "method=post" in the form, so i don't know hot to transmit the form-data.
The html-part (from http://www.reinvest24.com/en/login) looks like this:
<form>
<div class="form-group">
<input type="text" id="email" placeholder="Email" value="" name="email" maxLength="100" class="form-control"/>
</div>
<div class="form-group">
<input type="password" id="password" placeholder="Password" value="" name="password" maxLength="100" class="form-control"/>
</div>
<p class="forgot text-right">
<span>Forgot password?</span>
</p>
<input type="submit" class="btn btn-success" value="Login"/>
<p class="reg text-center">
<span>Don't have an account?</span>
<a href="/en/registration">
<span>Sign up</span></a>
</p>
</form>
So without the method clarified, I tried
final = s.get(loginUrl, data = payload)
but without success. The result in both cases is a html-output saying something about "Loading authorization details...".
So my question is: Am i missing the right method (POST/GET) to transmit data or am i missing some other parameter? Some websites require a session-token, which I retrieve from the login-site itself (like it's the case in https://www.mintos.com/de/login), but in my opinion, this is not the problem here.
By default, the body (form data) of a HTTP request is ignored when the method is set to GET. Therefore you shouldn't try to submit the request via GET (not only is it not safe to transmit sensitive info over GET, the server would just ignore the username/password of your request).
The issue here is that the page is doing some JavaScript magic to submit your request over a different URL. Open up your web inspector and watch the "network" tab whenever you try to login on that website. You should see that the request is being POSTed to https://api-frontend.reinvest24.com/graphql.
When we inspect this POST request, we can see that the data is being transmitted as a JSON body, not a form body. So your request should look something along the lines of this:
login_url = 'https://api-frontend.reinvest24.com/graphql'
payload = {
"operationName": "login",
"variables": {
"email": EMAIL,
"password": PASSWORD
},
"query": "mutation login($email: String!, $password: String!) {\n login(email: $email, password: $password)\n}\n"
}
r = s.post(url=login_url, json=payload)
# note that we used the 'json' parameter here not 'data'
Chrome web inspector is your friend here to observe how data is transmitted when logging in.
Good luck!

Use existing html page elements (its form and button) withing django app

My goal is to run python function when a user clicks on a button within a form on my web page, when the argument is taken from textarea HTML element.
The following html code is my form with button within and is part of django application.
<div id="contact_form" class="col_400 float_l">
<form id="demoForm" name="contact" >
<label for="text">Your Review:</label>
<textarea id="text" name="text" rows="0" cols="0" class="required"></textarea>
<div class="cleaner_h10"></div>
<input type="button" onclick="return Button1_onclick()" class="submit_btn float_l" name="submit" id="predictSentBtn" value="Predict" />
</form>
</div>
I looked on django.forms and django.forms.widgets, but still don't understand how to "link" between existing html elements and python objects.
This should help:
<div id="contact_form" class="col_400 float_l">
<form id="demoForm" name="contact" >
<label for="text">Your Review:</label>
<textarea id="needid" name="needid" rows="0" cols="0" class="required"></textarea>
<div class="cleaner_h10"></div>
<input type="button" onclick="return Button1_onclick()" class="submit_btn float_l" name="submit" id="predictSentBtn" value="Predict" />
</form>
def function(request):
if request.method = 'POST':
print request.POST['needid'] # print request.POST.get('needid')
Try it ;)

Categories

Resources