I am wondering how to accomplish the below with Django:
Consider a function in JavaScript:
$('#button').click(function(){
var rand_val = Math.random();
// here some code sends this rand_val to a Python script in Django app
// as seen below, script is run and generates result
alert('This is the result ' + result);
})
The script in the Django app:
def my_func(rand_val):
# result = (some operations with rand_val)
return result
The Python script will be run in Django virtual environment.
With a button click, run a Python script and show the result on the page.
You can send the data with ajax get,
var url = "url_to_my_func_view/" + rand_val
$.get( url, function( data ) {
alert( "Data Loaded: " + data );
});
You will need to return your result as bytes or JSON using HttpResponse or JsonResponse.
Edit:
If you need to send back user input (as the OP explained in the comments), then you are better off with GET or POST params. In JS you would do like so,
var url = 'url_to_my_func_view/'
$.get( url, {'user_val': rand_val}, function( data ) {
alert( "Data Loaded: " + data );
});
Then in your view you would catch those params like so,
def my_func(request):
user_val = request.GET['user_val']
return user_val
Notice that your function receives a request!
Hope this helps!
To perform form submission through Ajax, need to use some specific code snippets. I am adding the details source code so, you might find these helpful!
The code in JavaScript file:
//The functions below will create a header with csrftoken for Ajax based submission in Django application
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// Ajax setup end
$('#button').click(function(e){
var rand_val = Math.random();
$.post('/my_func/', { rand_val: rand_val }, function(data){
return false;
});
e.preventDefault();
});
In views.py:
def my_func(request):
response = {}
if request.method == 'POST':
rand_val = request.POST.get('rand_val')
# result = (some operations with rand_val)
return result
In urls.py: Django v2.x
from django.contrib import admin
from django.urls import path, include
import APP_NAME.views
urlpatterns = [
path('my_func/', APP_NAME.views.my_func),
]
Expecting the code will work for you!
Related
I am currently trying to write some Javascript to interact with an API that I deployed on GAE (using Python) using XMXMLHttpRequest(). I've had no issue getting a GET, however the PUT is giving me a lot of trouble.
Interestingly, I have no issue touching the PUT request from a test HTTP site (https://www.hurl.it/), however I receive a status value of 0 every time I try from my own Javascript code. Below are snippets of my GAE and Javascript code.
(NOTE - I must use a "put" for this call as a requirement.)
Any guidance would be appreciated!
GAE (Server):
def put(self):
# Save variables for update
cardkey = self.request.get('key', default_value=None)
ident = self.request.get('ident', default_value=None)
brand = self.request.get('brand', default_value=None)
year = self.request.get('year', default_value=None)
player = self.request.get('player', default_value=None)
# If card key is provided then update card
if cardkey:
# Get card
card_to_update = ndb.Key(db_models.Card, int(cardkey)).get()
if ident:
card_to_update.ident = ident
if brand:
card_to_update.brand = brand
if year:
card_to_update.year = year
if player:
card_to_update.player = player
# Save changes and print update to requester
card_to_update.put()
card_dict_format = card_to_update.to_dict()
self.response.write(json.dumps(card_dict_format))
return
# If card key is not provided send error
else:
self.response.write('key not provided. must provide key for update.')
return
And the Javascript from my webpage:
<script>
window.onload = function()
{
var myRequest = new XMLHttpRequest();
var url = 'http://cs496-assignment3-mastrokn.appspot.com/updatecard';
var param = 'key=5636318331666432';
myRequest.open('put', url);
myRequest.onreadystatechange = function()
{
if ((myRequest.readyState == 4) && (myRequest.status == 200))
{
// var myArr = JSON.parse(myRequst.responseText);
// myFunction(myArr);
document.getElementById("viewCards").innerHTML = myRequest.status;
}
else
{
document.getElementById("viewCards").innerHTML = myRequest.status;
}
}
myRequest.send(param);
}
</script>
First, your onreadystatechange() handler should look like this:
myRequest.onreadystatechange = function()
{
if (myRequest.readyState == 4) //Don't do anything until the readyState==4
{
if(myRequest.status == 200) //Check for status==200
{
document.getElementById("viewCards").innerHTML = myRequest.status;
}
else //All other status codes
{
document.getElementById("viewCards").innerHTML =
'readyState='
+ myRequest.readyState
+ ' status='
+ myRequest.status
+ ' status text='
+ myRequest.statusText;
}
}
}
Then, from the docs:
If you end up with an XMLHttpRequest having status=0 and
statusText=null, it means that the request was not allowed to be
performed. It was UNSENT.
To see what went wrong, check the javascript console in your browser for an error, e.g.:
[Error] XMLHttpRequest cannot load
http://cs496-assignment3-mastrokn.appspot.com/updatecard. Origin
http://localhost:4567 is not allowed by Access-Control-Allow-Origin.
(4.htm, line 0)
When I run the code above and send the XMLHttpRequest to my own local server, the PUT request succeeds with a status code of 200.
Lastly, I have doubts about the server code you posted because I don't know of any framework where you return None from a request handler--rather you return some string or a response object. Yet, using other means to make a PUT request to your url returns a 200 status code. Is that really your server code? What framework are you using?
I have the following code, and node.js can't resolve the url:
const request = require('request')
const teamURL = `/users/${user._id}/teams`;
const req = request({
url: teamURL,
json: true
},
function(error, response, body) {
if (!error && response.statusCode == '200') {
res.render('userHome.html', {
user: user,
teams: body
});
}
else {
console.error(error);
next(error);
}
});
is there a good way to use relative paths/urls with the request library on a server-side node.js Express app?
Giving just a relative url only works if it is clear from context what the root part of the url should be. For instance, if you are on stackoverflow.com and find a link /questions, it's clear from context the full url should be stackoverflow.com/questions.
The request library doesn't have this kind of context information available, so it needs the full url from you to do be able to make the request. You can build the full url yourself of course, for instance by using url.resolve():
var url = require('url');
var fullUrl = url.resolve('http://somesite.com', '/users/15/teams');
console.log(fullUrl); //=> 'http://somesite.com/users/15/teams');
But of course this will still require you to know the root part of the url.
Jasper 's answer is correct -- the request module needs full URL. if you are in a situation where you have a single page application, with lots of requests to an API with the same base URL, you can save a lot of typing by creating a module like this:
var url = require('url');
var requestParser = (function() {
var href = document.location.href;
var urlObj = url.parse(href, true);
return {
href,
urlObj,
getQueryStringValue: (key) => {
let value = ((urlObj && urlObj.query) && urlObj.query[key]) || null;
return value;
},
uriMinusPath: urlObj.protocol + '//' + urlObj.hostname
};
})();
then, to grab the base URL anytime you need it: requestParser.uriMinusPath
and grab the value of an arbitrary query parameter: RequestParser.getQueryStringValue('partner_key');
My goal is to intercept every outgoing message from my server in a meteor project and add some stuff (meta datas and additional contents)
I have this simple code :
var http = Npm.require( 'http' ),
originalWrite = http.OutgoingMessage.prototype.write;
http.OutgoingMessage.prototype.write = function ( chunk, encoding ) {
console.log( this, arguments );
chunk = chunk.replace( 'some code', 'elements to add' );
originalWrite.call( this, chunk, encoding );
}
It works but I cannot find the url of the current call. This is a problem because I need to add different elements according to the called url.
(nota : I have a condition to make sure the request is an html file)
The full URL isn't directly available but host and path are through the request header Host and a property path on the OutgoingMessage object.
To obtain the full URL:
var url = this.getHeader('host') + this.path; //or this._headers.host;
--
var originalWrite = http.OutgoingMessage.prototype.write;
http.OutgoingMessage.prototype.write = function () {
var url = this.getHeader('host') + this.path;
//...
return originalWrite.apply(this, arguments);
};
The reason path isn't available in the header is because the request path is part of the Request-Line. The OutgoingMessage implementation first establishes a TCP connection to the host and then issues a request on the path.
GET /path HTTP/1.1
Host: hostname
I understand the notion of the same-origin policy and the reasons for it, and I understand that cross-domain requests are possible with CORS. But I'd like to know if it's in any way possible, however unconventional it may be, to communicate with a server cross-domain when that server does not return the "Access-Control-Allow-Origin" header in responses.
I'm not trying to attack anything. I just want to legitimately login to a web application (I don't own the web app) from a remote domain and trigger some selected functionality that will result in retrieving some data.
Could someone tell me if this is even possible and how I might go about it. If it's not possibe to do an ajax call directly, then maybe even embed a hidden iframe containing the target web app in my own site and manipulate it somehow?
you can use yahoo query language for getting arround that :D
heres an extended jquery ajax function for dooing so
jQuery.ajax = function (e) {
function o(e) {
return !r.test(e) && /:\/\//.test(e)
}
var t = location.protocol,
n = location.hostname,
r = RegExp(t + "//" + n),
i = "http" + (/^https/.test(t) ? "s" : "") + "://query.yahooapis.com/v1/public/yql?callback=?",
s = 'select * from html where url="{URL}" and xpath="*"';
return function (t) {
var n = t.url;
if (/get/i.test(t.type) && !/json/i.test(t.dataType) && o(n)) {
t.url = i;
t.dataType = "json";
t.data = {
q: s.replace("{URL}", n + (t.data ? (/\?/.test(n) ? "&" : "?") + jQuery.param(t.data) : "")),
format: "xml"
};
if (!t.success && t.complete) {
t.success = t.complete;
delete t.complete
}
t.success = function (e) {
return function (t) {
if (e) {
e.call(this, {
responseText: t.results[0]
}, "success")
}
}
}(t.success)
}
return e.apply(this, arguments)
}
}(jQuery.ajax);
this will send the request to yql which has the correct accept-headers, and yql will return the content of the url requested even if it does not have the correct headers
I am using a function called $.ajaxSend instead of $.ajax to send AJAX post requests. When I just add the ajaxSend function to the bottom of the JS file, I get a 403 forbidden when I try to do post requests on the remote machine, but the local machine works. Here is the error I get when I try to do an AJAX post call:
Uncaught TypeError: Object function (a,b){return new e.fn.init(a,b,h)} has no method 'ajaxSend'
Here is what the script looks like:
$.ajax({
... do post stuff ...
});
$(document).ajaxSend(function(event, xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
I got the code from here: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
I tried following these instructions but they didn't work:
error: "CSRF verification failed. Request aborted." when using jquery ajax with Django
The .ajaxSend has to be attached to a jQuery object (like in Django example: to the $(document) object, not $ itself). This function is not for doing AJAX, but for setting AJAX before it fires. So you should use $.ajax({...}); in the first line (the Django code is fine). See the documentation for details.
The real question is: how can this code work locally? :)