I have a Django WSGI (not my decision) website making a call to fetch dynamically generated JavaScript. I put the function in views.py and it's receiving the request and doing the work, but the return value is being rejected.
The HTML (JavaScript section of web page) that calls this function does it like this:
var jscript = document.createElement('script');
jscript.id = 'generate';
jscript.style.visibility = 'hidden';
jscript.style.display = 'none';
jscript.src = `/generate?callback=catchOptions${query}`; // jsonp https://en.wikipedia.org/wiki/JSONP query is a list of parameters in query string format
if (document.getElementById("generate") == null)
document.body.appendChild(jscript); // javascript needs this to work properly
There's map file that maps /generate to /generate_planet (see below). Getting into the function works great. It's the return value that Djangoff is rejecting.
Here is the function in views.py
from cgitb import reset
from django.shortcuts import render
from . import planetor
from django.http import JsonResponse
def generate_planet(request):
res = planetor.generate(request.content_params, "/app/planetor/", "FRAMES=1")
# res is JSON text, NOT a python dict
return res
# res looks like this:`callback({'camera_location': '-30,-30,-30', 'camera_angle': '30', 'sun_color': '5,5,5', 'sun_position': '10000,0,-10000', 'planet_size': '20.06', 'background': 'background_2.jpg', 'planet': 'surface_1.jpg', 'clouds_size': '1.02', 'clouds': 'clouds_16.jpg', 'clouds_density': '0.80', 'atmosphere': 'iodine', 'atmosphere_density': '0.95', 'atmosphere_size': '1.03', 'moons': '4', 'moon_position': None, 'moon_size': None, 'moon': None, 'random_color': None, 'random_float': None, 'random_trans': None, 'star_system': 'Barnard', 'star_index': 'Zeta', 'planet_index': 'II', 'planet_type': 'Surface ', 'identity': '81654447928', 'designation': 'v_star_index v_star_system v_planet_index', 'clouds_file': 'clouds_16.jpg'})
The function call actually works, and the "planetor.generate()" runs. The problem is, the return JSON (JSONP really) from this, is rejected by Djangoff
Djangoff spits out this:
Internal Server Error: /generate_planet
Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/usr/local/lib/python3.9/dist-packages/django/utils/deprecation.py", line 119, in __call__
response = self.process_response(request, response)
File "/usr/local/lib/python3.9/dist-packages/django/middleware/clickjacking.py", line 33, in process_response
response.headers['X-Frame-Options'] = self.get_xframe_options_value(
AttributeError: 'dict' object has no attribute 'headers'
[05/Jun/2022 16:52:11] "GET /generate_planet? HTTP/1.1" 500 56694
It's looking for the return value to be wrapped in something I'm sure but for the life of my I can't find 1) any API documents for WSGIResponse to I can construct one and 2) examples of anyone doing anything like this with Djangoff
I eventually figured this out.
If you send a request to Django, like this:
/my_request?key1=value1&key2=value2&key3=value3
By whatever means (raw URL, form submit, ajax request, whatever)
To have Django catch that request and return a JSON answer put a function like this in views.py
def my_request(request):
selections = request.GET # <== this gets the query string paramaters as a dictionary
# use the query string parameters as the parameters of the function for creating the answer to the request
res = {"answer1":"value1","answer2":"value2"} # << python dictionary of answer
return JsonResponse(res) # convert dictionary to JSON
If you want to get JSONP back, you'll have to just code the raw javascript:
return 'callback({"answer1":"value1","answer2":"value2"})'
Related
I have managed to send & receive my JSON object in my views.py with a POST request (AJAX), but am unable to return render(request, "pizza/confirmation.html"). I don't want to stay on the same page but rather have my server, do some backend logic on the database and then render a different template confirming that, but I don't see any other way other than AJAX to send across a (large) JSON object. Here is my view:
#login_required
def basket(request):
if request.method == "POST":
selection = json.dumps(request.POST)
print(f"Selection is", selection) # selection comes out OK
context = {"test": "TO DO"}
return render(request, "pizza/confirmation.html", context) # not working
I have tried checking for request.is_ajax() and also tried render_to_string of my html page, but it all looks like my mistake is elsewhere. Also I see in my terminal, that after my POST request, a GET request to my /basket url is called - don't understand why.
Here is my JavaScript snippet:
var jsonStr = JSON.stringify(obj); //obj contains my data
const r = new XMLHttpRequest();
r.open('POST', '/basket');
const data = new FormData();
data.append('selection', jsonStr);
r.onload = () => {
// don't really want any callback and it seems I can only use GET here anyway
};
r.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
r.send(data);
return false;
In your basket view function, you always render the template as response. You can pass the parameters to your js snippet via HttpResponse. After request completed and you have response in your js function, you can use window.location.href to redirect the page you want. You can also look this answer to get more information.
I am trying to build a java online compiler web app using django.
but every time I submit my code through AJAX call the new code is posted successfully to view.py but the JSON response object is still the previous one.
def code1(request):
response_data={}
**codet=request.POST.get("code","")** # getting the code text from Ajax req
**output=code(codet)** #sending code for execution
response_data['result']="Successful" #storing in response
response_data['message']=output
**return HttpResponse(json.dumps(response_data), content_type="application/json")**
def code(code_text):
return execute(code_text)
def execute(code_text):
filename_code=open('Main.java','w+') #creating file
filename_code.flush()
f1 = code_text.split("\n") # splitting code line by line
for i in f1:
filename_code.write(i+"\n") #writing code line by line
filename_code.close() #closing file
time.sleep(2) #giving wait
**compile_java(filename_code)**
#compiling file (Note: I am not using the file passed in compile_java)
**return execute_java(filename_code,input**) #running java file
def compile_java(java_file):
proc = subprocess.Popen('javac Main.java', shell=True)
def execute_java(java_file, stdin):
#java_class,ext = os.path.splitext(java_file)
cmd = ['java ', 'Main']
proc = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
stdout,stderr = proc.communicate(stdin)
stdoutstr= str(stdout,'utf-8')
**
1. return stdoutstr
**
Actually the previous json response is being sent for current code(codet)
This question already has answers here:
jQuery posting JSON
(3 answers)
Submit a form using jQuery [closed]
(22 answers)
Closed 5 years ago.
I have read several postings on different examples for passing a javascript variable to flask through post/get forms. I still don't understand how to do this. From my understanding, the form creates a post/get that can then be called and received by the python flask script. Can someone write up a very simple example on what this should look like?
Starting from creating a variable with any value in javascript and then making the post/get. Lastly what should the receiving end on python should look like and finally print the variable from python.
How I did this was using an ajax request from the javascript which would look something like this. I think the easiest way would be using JQuery as well since it might be a bit more verbose with pure javascript.
// some movie data
var movies = {
'title': movie_title,
'release_date': movie_release_date
}
$.ajax({
url: Flask.url_for('my_function'),
type: 'POST',
data: JSON.stringify(movies), // converts js value to JSON string
})
.done(function(result){ // on success get the return object from server
console.log(result) // do whatever with it. In this case see it in console
})
Flask.url requires JSGlue which basically let's you use Flask's
url_for but with javascript. Look it up, easy install and usage. Otherwise I think you could just replace it with the url e.g '/function_url'
Then on the server side you might have something like this:
from flask import request, jsonify, render_template
import sys
#app.route("/function_route", methods=["GET", "POST"])
def my_function():
if request.method == "POST":
data = {} // empty dict to store data
data['title'] = request.json['title']
data['release_date'] = request.json['movie_release_date']
// do whatever you want with the data here e.g look up in database or something
// if you want to print to console
print(data, file=sys.stderr)
// then return something back to frontend on success
// this returns back received data and you should see it in browser console
// because of the console.log() in the script.
return jsonify(data)
else:
return render_template('the_page_i_was_on.html')
I think the main points are to look up ajax requests in jquery, flask's request.json() and jsonify() functions.
Edit: Corrected syntax
I call
$.getJSON('http://localhost:8000/polls/?callback=?', function(data)
and recieve an error:
Error: parsererror errorThrown: jQuery16103397698865741826_1320825997345 was not called
If I call a json file that is next to my html file it works fine.
If I call the google example url: http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-c.json&callback=? it also works.
Any ideas? I think that maybe it has something to do with DJango or the way I return from my server side code.
index(request):
a = {}
a[1320675940] = 1.8
a[1320675941] = 2.8
a[1320675942] = 38
a[1320675943] = 4.8
a[1320675944] = 5.8
a[1320675945] = 6.8
a[1320675946] = 7.8
data = simplejson.dumps(a)
return HttpResponse(data, mimetype="text/plain")
#return HttpResponse(data, mimetype="json")
#return HttpResponse(str(data), mimetype="text/plain")
You are returning JSON (with a plain text content-type), not JSON-P.
You need to look at the value of callback in the query string and wrap the JSON in that function call.
e.g. for ?callback=foo:
foo(/* Your JSON here */);
You should also use the correct content type (application/javascript).
I've been tyring to figure out how to load JSON objects in Python.
I'm able to send a JSON string to the server, but there it fails.
This is what I'm sending through a websocket with JavaScript:
ws.send('{"test":"test"}');
The server receives it without a problem, but can't validate it:
{"test":"test"}
This is not a JSON object!
Which comes forth from this code:
try:
data = data[:-1]
json.loads(data)
except ValueError:
print 'This is not a JSON object!'
else:
print ('JSON found!')
The data = data[:-1] is there to strip the delimiter sent through the websocket.
import traceback
try:
d = json.loads(data[data.index('{'):-1])
except:
traceback.print_exc()
else:
print(d)
This way only the dictionary part of the data-string is parsed to json.loads().