I wrote a simple form. For some reason, the form sends always GET requests instead of POST.
CODE EXAMPLE
<form action="{{ url_for('home') }}" method="post">
<div class="row">
<div class="col-sm-12">
<input type="text" required dir="rtl" name="name" class="form-control" id="Name" placeholder=" שם ">
</div>
<div class="col-sm-12">
<input type="tel" required dir="rtl" name="phone" class="form-control" id="Phone" placeholder=" פלאפון ">
</div>
<div class="col-sm-12">
<input type="email" dir="rtl" name="email" class="form-control" id="Email" placeholder=" דוא'ל ">
</div>
<div class="col-sm-12">
<textarea class="form-control" dir="rtl" name="text" rows="5" id="Message" placeholder=" הודעה "></textarea>
</div>
<div class="col-sm-12 col-md-12 c-c-padding">
<button type="submit" name="send" id="contact_submit" class="btn btn-dm"> שלח </button>
</div>
</div>
</form>
SERVER SIDE
#app.route('/', methods=["GET", "POST"])
def home():
print(request.method)
if request.method == 'POST':
name = request.form['name']
phone = request.form['phone']
email = request.form['email']
print(name + phone + email)
if phone:
requests.post('DOMAIN',
auth=("api", 'API'),
data={"from": "Email",
"to": ["email"],
"bcc": "",
"subject": " ",
"text": """ Name: {}
Phone: {}
Email: {} """.format(name, phone, email)})
flash(' welldone ', 'success')
return redirect(url_for('home'))
else:
flash(' phone ', 'warning')
return redirect(url_for('home'))
return render_template('index.html')
After I press the 'submit' button. As I said, it sends GET request instead of a POST.
Then something weird happens. It injects 'index.html' into the form - and what happens, is that I have a website inside the website.
First, what should I do to fix the problem of sending POST request instead of GET request.
Second, why 'render_template()' injects the HTML into the form? Instead render the whole page?
Replace
return redirect(url_for('home'))
with
return redirect(request.url)
or
return redirect(request.referrer)
Why? If we read the docstring for url_for():
Generates a URL to the given endpoint with the method provided
We see that redirect(url_for('home')) tells Flask to redirect the client to the home() endpoint, which then calls redirect(url_for('home')) and so on in a looping cycle.
When needed, call redirect(url_for('home')) from endpoints different than home().
From the docstrings for request.url and request.referrer:
request.url :
The full request URL with the scheme, host, root path, path,
and query string.
request.referrer :
The Referer[sic] request-header field allows the client
to specify, for the server's benefit, the address (URI) of the
resource from which the Request-URI was obtained (the
"referrer", although the header field is misspelled).
You can read more about them from these SO answers.
Related
I've cloned a flask chat app respo on Git (link: https://github.com/techwithtim/Chat-Web-App). But when I logged in and try to send a message from the form, the server said that The method is not allowed for the requested URL.
I'm not sure because the Database file is separated, however I think the issues is in the
#view.route("/")
#view.route("/home")
def home():
"""
displays home page if logged in
:return: None
"""
if NAME_KEY not in session:
return redirect(url_for("views.login"))
return render_template("index.html", **{"session": session})
#view.route("/get_messages")
def get_messages():
"""
:return: all messages stored in database
"""
db = DataBase()
msgs = db.get_all_messages(MSG_LIMIT)
messages = remove_seconds_from_messages(msgs)
return jsonify(messages)
and the send message is index.html like
<div class="container">
<div id="messages" class="overflow-auto msgs" style="overflow-y: scroll; height:500px;">
</div>
<form method="POST" id="msgForm" action="" style="bottom:0; margin: 0% 0% 0% 0%;">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Message" aria-label="Message" id="msg">
<div class="input-group-append">
<button class="btn btn-success" type="submit" id="sendBtn">Send</button>
</div>
</div>
</form>
</div>
Getting a 400, when trying to upload a file ad send other form elements to flask from html. Tried to use ajax, but that throws me an error as well.
Python:
#app.route('/prod_diff_result', methods=['POST', 'GET'])
def prod_diff_result():
try:
host = request.form['host-prod-iterator']
print(host)
if request.files['file']:
f = request.files['file']
f.save(secure_filename(f.filename))
HTML:
<div class="main-div">
<form action="/prod_diff_result" method="POST" enctype="multipart/form-data">
<div class="grid-container">
<div class="grid-item">
<span class="label label-default ">PROD</span><br>
<p>Iterator Host : <input type="text" class="form-control" id="host-prod-iterator" value="10.47.7.57"
required></p>
<input type="radio" name="data_fetch_type" value="file" onclick="showfile()">Upload File
<input type="file" name="file" />
<input type="radio" name="data_fetch_type" value="db"> Get from DB
<input type="submit" />
</div>
</form>
</div>
I want to be able send hostname and file back to flask error in one request and using one form.
It gives an error because you try to access a form field that it cannot find, and assumes that somehow the request was bad, because it didn't include a required form field. You are trying to access:
host = request.form['host-prod-iterator']
However you have simply not given it a name in your HTML. If you give it a name, it should work:
<p>Iterator Host :
<input type="text" class="form-control" name="host-prod-iterator" id="host-prod-iterator" value="10.47.7.57" required>
</p>
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!
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.
I tried to upload two files woth two different location but when uploading files, I'm getting this error "ValueError: View function did not return a response". I tried everything to get it works but no luck.
html code:
<form action="/NewCases/" method=post class="form-horizontal">
<h2>Add New Cases: </h2>
<div class="input-group">
<span class="input-group-addon">#</span>
<input type="text" id="casename" name="casename" class="form-control"
placeholder="Enter Case Name:" required>
</div>
<div class="input-group">
<span class="input-group-addon">#</span>
<input type="text" id="adminname" name="adminname" class="form-control"
placeholder="Enter Case Name:" value="{{ current_user.username }}">
</div>
<div class="input-group">
<span class="input-group-addon">#</span>
<input type="file" id="imagefile" name="imagefile" class="form-control"
placeholder="Enter Hard Disk File:" required>
</div>
<div class="input-group">
<span class="input-group-addon">#</span>
<input type="file" id="memimagefile" name="memimagefile" class="form-control"
placeholder="Enter Memory File:" required>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-success">Signup</button>
</div>
</div>
</form>
flask code
#app.route('/NewCases/', methods=['GET', 'POST'])
def NewCase():
try:
if request.method == 'GET':
return render_template('admin.html', DICT=DICT)
if request.method == 'POST':
idtest = str(uuid.uuid4())
idtestfilter = idtest.replace('-','')
adname= request.form['adminname']
casen = request.form['casename']
imagefile = request.files['imagefile']
memimagefile =request.files['memimagefile']
if imagefile > 0:
imagefilename = secure_filename(imagefile.filename)
file.save(os.path.join(UPLOAD_FOLDER , imagefilename))
return redirect(url_for('index'))
if memimagefile > 0:
imagefilename = secure_filename(memimagefile.filename)
file.save(os.path.join(UPLOAD_FOLDER , memimagefile))
return redirect(url_for('index'))
c, conn = connection()
c.execute("INSERT INTO cases(id,casename, adminname, imagepath, memimagepath) VALUES (%s, %s, %s, %s, %s)",
(thwart(idtestfilter),thwart(adname),thwart(casen),thwart(imagefilename),thwart(memfilename)))
conn.commit()
flash("case inserted!")
c.close()
conn.close()
flash('Cases successfully added')
return redirect(url_for('EditCase'))
except Exception as e:
error = e
Please help me out!
The first thing to point out is that your Python code is failing, but you are catching and ignoring all exceptions (well, almost all). The main reason that your Python code is failing is because a bad request is being received. You would know that if you did not catch and ignore all exceptions. At least print a message, and raise the exception again.
Anyway, you are uploading files so you need to set the encoding type for your HTML form to multipart/form-data, like this:
<form action="http://127.0.0.1:5000/" method=post enctype="multipart/form-data" class="form-horizontal">
That's the cause of the bad request.
I assume that you have imported all required modules and functions such as uuid, secure_filename etc., however, you are not quite saving the files properly. Use imagefile.save() and memimagefile.save(), not file.save().
Also, because both files can be uploaded at the same time, and because there is database code that should be run, you should not return after saving the files.
Finally, your code assumes that the form fields will always be present in the form. If one is missing your code will fail with a KeyError.