How to pass data by 'POST' method to from Javascript to Python - javascript

I have this part of script from my GAE application which uses webapp2, which accepts data from a form using post,
class RenderMarksheet(webapp2.RequestHandler):
def post(self):
regno = self.request.get('content') # Here's where I extract the data from the form
...
...
...
self.response.out.write(template.render(templates/render.html, template_values))
And the web form which posts to this script,
<form action="/sign" method="post" name="inputform" onsubmit="return validate()">
Register No : <input type="number" name="regno" placeholder="Your Register No."/>
<input type="submit" value="Get-My-GPA!" >
</form>
Now, I want to manually pass a specific data (a register no.), without using the submit button from the form, to the python script( or the url, perhaps) , using Javascript, say a button that triggers a javascript method.
I have to POST the data using javascript(to implement AJAX).
In python I do this, to post the data to a url,
import http.client, urllib.parse
params = urllib.parse.urlencode({'regno':10109104021})
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
conn = http.client.HTTPConnection("mydomain:8888")
conn.request("POST", "/sign", params, headers)
response = conn.getresponse()
print(response.status, response.reason)
data = response.read()
How can I post the data to the url, via Jquery or Javascript?

fastest is to use jQuery and use $.post()

I'm not 100% sure what you're trying to do, but after several rereads here's what I think you're trying to do.
you'll need to import urllib2
#import google classes
import urllib2
class RenderMarksheet(webapp2.RequestHandler):
def parseResponse(self, response):
#run some code in here to parse the results since it's an HTML document ... beautifulsoup, perhaps?
def post(self):
regno = self.request.get('content')
rawlink = "http://result.annauniv.edu/cgi-bin/result/result11gr.pl?regno="
link = rawlink+regno
try:
result = urllib2.urlopen(link)
gpa = parseResponse(result)
except urllib2.URLError, e:
self.response.out.write(e)
template_values = {'gpa': gpa}
self.response.out.write(template.render(templates/render.html, template_values))
This method will
Take the input from the form
Build the link
Request information from the annauniv webserver
Parse the response from that server (you're on your own parsing that, but you'd have to do it regardless)
Store the GPA a templates dictionary for use in your template

Related

$_POST array empty in php after submission of a form using a formData

I've seen several posts about the issue but none of them solved my problem. I'm working with XAMPP and I have an html index.html and a php remote.php in the same folder.
The formData which I want to send to the php is created using a form (basic_form) in javascript. It resulted to be well constructed, since console.log(...formData); printed Array [ "mode", "basic" ], Array [ "file", File ] as expected, which are the string and the input file.
But unfortunately in the php the command print_r($_POST); outputs only Array() and also the command var_dump($_POST); outputs array(0){}. So it seems that the content of the form is not passed to the php.
Here it is the html form:
<body>
<div>
<form name="basic_form" enctype="multipart/form-data" action="remote.php" method="post">
<input type="text" id="mode" name="mode" value="basic"/>
<input type="file" id="file" name="file"/>
<input type="submit" id="submit_basic_input" name="submit_basic_input" value="Submit"/>
</form>
</div>
</body>
Here the javascript to submit the form:
<script>
var basic_form = document.forms["basic_form"];
basic_form.addEventListener('submit', e => {
e.preventDefault();
const url = 'remote.php';
const formData = new FormData(basic_form);
fetch(url, {
method: 'POST',
body: formData
}).then(response => {
console.log(response);
if(response["status"] == 200)
location.replace(response["url"]);
});
});
</script>
Here the php to print the content of form:
<?php
var_dump($_POST);
$datapost = $_POST;
print_r($datapost);
print($datapost["mode"]);
?>
First, you call fetch which makes a POST request
When you get a response, you log the response object (which doesn't hold anything all that useful, in particular the body of the response will show up as a readable stream and not a string).
That response does show array(1) { ["mode"]=> string(5) "basic" } Array ( [mode] => basic ) basic though, you can see it using the Network tab of the browser's developer tools.
After logging the response you set location.replace(response["url"]); which makes a GET request (to the same URL) and navigates the browser to it.
The GET request is a different request and does not have the request body from the POST request from it.
Since it is a different request, it gets a different response and now $_POST is an empty array.
If you want to navigate to the response then get rid of the JavaScript. Just make the POST request with the form and let the browser render the resulting page.
If you want to use Ajax to make the request then:
Don't immediately navigate away from the page
Do something useful with the response (starting by calling response.text() to get the data out of the response body and then perhaps using createElement, appendChild and friends to add the data to the current document)

How to send data from React to Flask then back to react and show output on DOM

Im trying to pass data from React --> Flask --> React and show it in the DOM.
So far I been able to:
Send data from React to Flask and display the output on the console. (POST)
Send data from flask to React and display it on the DOM (GET)
So now my confusion is how do I put these 2 together. Here is my React code to send my data to Flask Username.js (POST)
##REACT
class Content extends Component {
login = (e) => {
e.preventDefault();
axios
.post("/username", {
username: document.getElementById("username").value,
})
.then((res) => {
console.log( res.data);
});
};
render() {
return(
<div className="p"> <User />
<form onSubmit={this.login}>
<p>
<label htmlFor="email">Email</label>
<input
type="username"
className="w3-input w3-border"
id="username"
/>
</p>
<p>
<button type="submit" className="w3-button w3-blue">
Login
</button>
</p>
</form>
</div>
);
}
}
And here is how I receive my data on flask
###FLASK
#app.route("/username", methods=['POST'])
def login():
username = request.json["username"]
#username = request.args.get('username')
return {"username": 'This is the backend -- >'+ username }
When adding anything on my input label I can see it on the console. Now what I want is to get the result that I added on the input in the DOM. This can be on another page maybe?
Do I need to create a new route and pass the data from the /username? and then make an API call on my react app to this new route? How can I pass this username output to another route? Is this the right way of doing it?
Please advice thank you
from your front-end code it seems that you are sending a post request of type: application/x-www-form-urlencoded, that it's the default request for html5 form.
In your backend logic you're tring to get incoming data as json with the following code request.json["username"]. Instead you should use request.form["username"] or request.form.get("username", "").
Here a little resume:
request.args: the key/value pairs in the URL query string
request.form: the key/value pairs in the body, from a HTML post form,
or JavaScript request that isn't JSON encoded request.files: the
files in the body, which Flask keeps separate from form. HTML forms
must use enctype=multipart/form-data or files will not be uploaded.
request.values: combined args and form, preferring args if keys
overlap request.json: parsed JSON data. The request must have the
application/json content type, or use request.get_json(force=True) to
ignore the content type.
request.files: the files in the body, which Flask keeps separate from form. HTML
forms
must use enctype=multipart/form-data or files will not be uploaded.
request.values: combined args and form, preferring args if keys overlap
request.json: parsed JSON data. The request must have the application/json
content type, or use request.get_json(force=True) to ignore the content type.
Your input field in front-end code should look like this:
<form onSubmit={this.login} method="post">
<p>
<label htmlFor="email">Email</label>
<input type="username" className="w3-input w3-border" id="username" name="username" />
</p>
<p>
<input type="submit" className="w3-button w3-blue" value="Login" />
</p>
</form>
Changes added :
method="post" : default method in html 5 form is GET
name="username" : as new attribute for input
input type="submit" : instead of button
Your back-end should be like this:
#app.route("/username", methods=['POST'])
def login():
username = request.form.get("username", "") # or request.form["username"]
return jsonify(username=username) # from flask import jsonify
I advice you to use jsonify() to return json data.
Finally in your front-end code if you want to print json response with the collected username should update your code in something like this:
.post("/username", {
username: document.getElementById("username").value,
})
.then((res) => {
// JSON response is handled by a json() promises
return res.json().then( (data) => console.log(data));
});

Escaping xsrf in Tornado with javascript POST

I have a simple form I would like to submit to a Tornado POST and I am running xsrf in tornado. The following produces the known error: '_xsrf' argument missing from POST
Has anyone solved how to submit the xsrf (like {% module xsrf_form_html() %}) in a regular HTML form using javascript? Here is the code:
<form action="#" id="form_field">
{% raw xsrf_form_html() %} # DOES NOT WORK!
<p><input type="text" id="field1" value=""></p>
</form>
<button id="button">UPDATE</button>
<script>
button.onclick = function changeField() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/chatdata", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
value: document.getElementById("field1").value
}))
};
</script>
xsrf_form_html is for traditional html forms using x-www-form-urlencoded. It won't be recognized if you submit your form as JSON. To use non-form-based encodings with Tornado's XSRF protection, pass the XSRF token as a X-XSRF-Token X-XSRFToken HTTP header.
According to the documentation page you would just create a request that has a _xsrf request field, for example a x-www-urlencoded string of _xsrf=yourtoken. The way you had it you were sending just some JSON that had a value property, ie {"value":"token"}.
Now you can get the token in a couple ways from what I have seen, either through a set cookie or from the field that is generated from the xsrf_form_html() call.
From cookie
//helper function to read cookie, from http://www.tornadoweb.org/en/stable/guide/security.html sample
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
var data = "_xsrf="+getCookie('_xsrf');
//note using this method you don't set the content-type,
//you want it to default to x-www-urlencoded
xhr.send(data);
Note you would have to build up the string to contain your other input form fields, either directly or through library methods like jQuery's serialize()
If want to just use the data straight from the form without the hassle of grabbing each input and generating a proper x-www-urlencoded string yourself; Then continue using xsrf_form_html() and create a FormData object from that form and send that. When you pass a form element to FormData() it will collect all the input values for you.
var data = new FormData( document.getElementById('form_field') );
//again no need to set the content-type as it will be automatically set internally
xhr.send(data);
//You could also use library methods like jQuery's serialize()
var data = jQuery('#form_field').serialize();
xhr.send(data);
Using FormData helps if you don't know how to get a reference to the generated field directly. Though it would more than likely have name="_xsrf" so a selector like input[name="_xsrf"] should find it. Though you would have to look at the generated html to find out.
var data = "_xsrf="+document.querySelector('input[name="_xsrf"]').value

#app.route not working without redirection

This function is working perfectly if I do a redirect to another page #app.route('/results') but I'm struggling to make it work in the same page without reloading :
#app.route('/')
def static_file():
return app.send_static_file('index.html')
#app.route('/')
def results():
headers = {
'X-ApiKey': 'xxxxxxxxxxxxxxxx',
}
data = {'data': request.args.get('data')}
results = requests.post('https://apiv2.indico.io/personality', headers=headers, data=data)
return results.text
I'd like to display the results of the api call in the same page (below the input box)
<form action="" onsubmit="return false";>
<strong> Try It <br><br>
</strong><br>
<input type="text" name="data"><br><br>
<input type="submit" onclick="showResults();">
<label id:Results>Your Result: </label>
<p><span id='display'></span></p>
</form>
I've also added some JS:
<script language="JavaScript">
function showResults() {
document.getElementById('display').innerHTML =
document.getElementById("Results").value;
}
</script>
What's wrong with my code? I'm using Flask framework.
If I understood you correctly, what you want to achieve is to have RESTful API written in Flask microframework, which would allow you to obtain some results and display on your page without reloading. If so, your approach is wrong.
Firstly, you can't route multiple functions with common URL:
#app.route('/common_route')
def foo():
pass
#app.route('/common_route')
def bar():
pass
It is impossible to determine which function did you want to be invoked if you load http://yourwebsite/common_route.
In order to avoid page reloading, you should rather use Flask-RESTful module and implement an API for obtaining results.
import flask-restful
class Results(Resource):
def __init__(self):
super(Results)
#for GET requests
def get(self):
#your code here
pass
#for POST requests
def post(self):
#your code here
pass
api = Api(app)
api.add_resource(Results(),'/api/results')
Then you can obtain your results f.e. with JS & jQuery code: https://www.w3schools.com/jquery/jquery_ajax_get_post.asp

Why do I get a 'CSRF token missing or incorrect' error?

I am trying to return a value from a View function in Django. That function is being called from a JavsScript code using Ajax, but I get thrown an error which reads 'Forbidden (CSRF token missing or incorrect)'.
JavaScript/Ajax
The Error message
The HTML code looks something like this:
<div align="center" class="input-line">
<form class="input-form" method="post">{% csrf_token %}
<input type = "text" id = "ans" class = "form-control" name = "address" placeholder="Type postcode..."><br><br>
<button id = "homeBtn" class="btn btn-primary">Find info</button><br><br>
</form>
</div>
The View Function is:
def result(request):
if(request == 'POST'):
param = request.form['my data']
this = runAreaReview(param) #This returns a string
return HttpResponse(this)
method 1
For making post requests with ajax, you need to set a header called HTTP_X_CSRFTOKEN and set it's value to a cookie which is stored in the browser by name csrftoken. Reference.
so in your ajax call, you should do something like this.
var csrftoken = Cookies.get('csrftoken');
$.ajax(
...
headers:{"HTTP_X_CSRF_TOKEN":csrftoken}
);
also note that if you are using some reverse proxy server with something like nginx, make sure to froward this header as well to the django application.
method 2
you can disable csrf verification for this specific view by using an annotation. Reference
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def result(request):
...
method 3
The method below is NOT RECOMMENDED for security reasons
You can alwaws turnoff the csrf middleware in settings to get rid of it if you are just building something for recreational purpose and not for production.
for any one come across this thread, the HEADER key should be X-CSRFToken as for Django 2.1, links goes here https://docs.djangoproject.com/en/2.1/ref/csrf/

Categories

Resources