Alternative render of JSON response in Django depending on request origination - javascript

I'm trying to find a way how to return JsonResponse which would be either interpreted as JSON when received by Ajax success function, or will be rendered to 404 (or any other page) if will be called directly via URL.
The reason I'm looking for this is because on my website I have few places where I am using empty modal view (pop-up) which is later populated with proper HTML content by server based on Ajax request.
In return JSON to my Ajax success function I have only HTML responsible for the modal content. So, when displayed as standalone (by typing GET request url directly in browser) it is JSON object.
What I'd like to achieve is display some page in such case (directly typed url for GET request), which will inform user that he's in wrong place, but at the same time will be properly understood by Ajax.
So far I've considered two approaches:
Use POST request - this is ok, until I need to render form in modal which is then sent back, also as a POST request, to server to be somehow processed. It requires some ugly workarounds to figure out if request is to render form and send HTML back, or to process form. In this approach I can return 404 page simply using http_method_not_allowed function.
Render JSON response using return render(request, 'mytemplate', {'form_html': form_from_string}) - this requires change of Ajax request to use text dataType and some extra workarounds on JS side to extract form_html.
Is there any 3rd option to get it working as I've imagined it will work?

I'm not sure to fully understand your question, but you can use request.is_ajax() to determine if the request was made using Ajax.
It uses the header X-Requested-With to determine if the request was made from ajax context.
Example:
class MyView(View):
def dispatch(self, request, *args, **kwargs):
if not request.is_ajax():
raise Http404
return super().dispatch(request, *args, **kwargs)

Related

Returning HTML View vs. JSON Object with HTML using Flask & AJAX

I'm developing a single page Flask app using AJAX to navigate through my routes. For example, when a user clicks on a nav-link, a GET request is made with AJAX that calls a route like "/profile", which returns a JSON including the HTML to be replaced on the screen.
If I type an existing route in the browser without calling an AJAX request, the HTML will be returned as expected as a JSON and simply pasted as text on the screen. I would like to give users the ability to type routes in the address bar and have the page load instead of just pasting the JSON with the HTML. What is the proper way to instead return a view instead of simply the JSON from my Flask end-point if no AJAX request was made (someone just types in "/profile" in the browser without clicking the profile nav-link)?
My first thought is to pass some type of parameter as part of every AJAX request and have the backend check if the parameter exists upon being called, where I would return a view instead of the JSON. That seems very inefficient and would make the code more complex by adding many more if statements. Additionally, I would have to create 2 HTML files for each route.
What is the proper way to go about this?
If you are making an ajax request, you can add this into your route.
_xhr_key = request.headers.get('X-Requested-With')
if _xhr_key and _xhr_key == 'XMLHttpRequest': # if true this means that its an AJAX call
#return data for AJAX function
else:
#return data for regular request
#render HTML template to the user over here since its a regular request
Ajax Requests make an XMLHttpRequest object
So if XMLHttpRequest object is present in the header then it means that it is an AJAX request. This is how you can load a webpage when a use normally loads it thus, you are able to render page using AJAX and when someone normally types the link in the browser

Send JSON data to Flask server using JQuery .load()

I am trying to use JQuery's .load() function to send data to my Flask server and, using that, render a <div> that is loaded into the calling element. My call looks something like this:
$("#element").load(
"/get_data",
{"info": info} // this is the problem
)
However, when I try to access this data in my Flask backend, the data is of form byte-string. (Accessing with request.get_data() yields a byte-string and request.get_json() yields None).
This did not surprise me, as the same behavior occurs when I use .ajax() requests. With Ajax, I simply use data: JSON.stringify({"info":info}) and that sends a string easily read by json.loads to the Flask backend just fine. What befuddles me is when I attempt the same data packaging with .load(), the request to the server is a GET instead of a POST.
Per .load()'s documentation, "The POST method is used if data is provided as an object; otherwise, GET is assumed." I don't understand why the data being a JSON string alters the behavior of .load() this way.
I'm keen to understand this behavior, but my question is how can I send data using JQuery's .load() to a Flask backend as a POST request in form JSON, or at least readable as a json (e.g. JSON string)?
Your code should work. You have data as {"info": info}, which is an object that .load should send as a POST. Make sure you are getting a JSON mimetype object from the server. Also, make sure your Flask view accepts the POST method:
from flask import Flask, request, Response
import json
#app.route('/get_data', methods = ['GET', 'POST'])
def get_data():
payload_dict = json.loads(request.data.decode('utf-8'))
# or try payload_dict = request.json
print(payload_dict["info"])
return Response(json.dumps({"info_response": "hello"}), mimetype='application/json')
And make sure you have info defined in {"info": info}
Thought about using getJSON: https://api.jquery.com/jQuery.getJSON/ ?

How to interface JQuery with Flask?

I'm writing a Google Chrome extension that uses a jQuery.post() call to send data to an external website. The external website handles the data using a Flask endpoint and generates a result. Unfortunately I am not sure how to transfer the result back to the client. How can I do this?
I've tried using a render_template call within Flask, like so:
app.route("/my_endpoint", methods = ['POST'])
def my_endpoint():
print ('hi') # this statement prints
results = ...
if request.method == 'POST':
# want to eventually replace this with
# return render_template("results.html", results=results)
return render_template("test.html")
But this doesn't actually load the page test.html.
I've also tried transferring the data back to the Chrome extension using a callback (which I would prefer not to do if possible), as in
post_results = function(input_data) {
jQuery.post("my_flask_endpoint",
input_data,
function (data, textStatus, jqXHR) {
...
}
But I'm not sure what to put in the callback function, because it seems like "data" is a bunch of HTML, and I don't know how to load pages given only an HTML string (as opposed to the URL).
It's good that data is a bunch of HTML, because that's exactly what you sent it! render_template is the Jinja2 function you use to show a given page to a user, and in the end, all that is is HTML. What you are doing is returning the HTML rendering of test.html as the data.
What (I think) you are trying to do, is either return the "results" object, or trigger a redirect to /results after POSTing to /my_endpoint?
Depending on what you plan to do with the data, you could go either way.
If you are wanting to return the data to the users current page/the jQuery callback, try just returning results as JSON (assuming results is a dictionary). A more detailed explanation of jsonify can be found here
return flask.jsonify(**results)
Alternatively, if you plan to navigate to a different page to show the results, you need to decide whether you want Flask to perform the redirection and render the data using results.html as a template, or pass the results to the client and have it navigate and transfer the received data itself.

what's the diffrence between $.ajax / $.get / $.POST / .load()?

I'm trying to understand AJAX and JSON and I'm not sure I get it, there are methods and functions that are doing the same stuff...
You've got $.getJSON to retrieve JSON format data from server, and you have $.ajax + $.post + $.get + load() to send data data to the server?
Can I use all of those methods to send JSON data?
Really I'm confused! Help me figure this out.
All those are just shorthands for calling the $.ajax function.
load is for retrieving HTML and writing it to the DOM in one go. You want to load JSON.
get and getJSON use GET requests which are not well-suited for sending JSON data.
post does a POST request, but doesn't allow you to choose the contentType of the sent data
For sending JSON you should use the $.ajax function with its many options, see Send JSON data with jQuery.
An AJAX request is, at heart, an HTTP request. This is the same protocol which is used for all content on the Web (arguably, if it's not HTTP, it's not the Web) - loading a page, the images on the page, the CSS and JS includes, a submitted form, etc, etc.
As such, it inherits pretty much all of the flexibility of HTTP, meaning a generic function like jQuery.ajax ends up quite complex, with lots of options you don't normally need to worry about. This leads to the Shorthand Methods you mentioned, which bundle up common sets of options and functionality.
Among the things you might want to vary:
The "method" of the request: GET or POST (or less common ones like HEAD, PUT, DELETE...). A GET request is the simplest: request this URL, give me its contents; parameters to a GET request are shoved onto the "query string" of the URL. A POST request is how larger forms would be submitted on a normal page: the parameters are passed as a body of data separate from the URL and control headers; for an AJAX request this is often helpful to send a block of XML or JSON to a URL. This is a very broad overview, and there are many more distinctions in behaviour and meaning between the two.
The "content type" you want in the response (and, for a POST request, of the data you're sending). Not only does this tell both the server and the browser what data it is handling, ensuring it will pass it successfully, it can give jQuery (or whatever library) a hint of what to do next: if a call returns XML, you'll probably want to manipulate it as a DOM straight away; if it's JSON, you'll want to parse it as a JS object.
What you want to do once the data comes back. I've already mentioned parsing JSON or XML, but what if your response is actually a block of HTML that you want to inject straight into the parent page? Obviously you could do that yourself in the callback function, but again jQuery includes a shorthand form in the shape of .load().
All of the above are possible with jQuery.ajax, but you'd have to remember the parameters, even though you're falling into the same cases again and again, so chances are most of the time you'll be using whichever of the shorthands suits your needs at that moment.

Pass ajax response to django template

I am learning to use javascript, ajax, python and django together.
In my project, a user selects a language from a drop-down list. Then the selected is sent back to the server. Then the server sends the response back to the django template. This is done by javascript. In the django template, I need the response, for example, German, to update the html code. How to pass the response to the html code. The response can be seen in the range of ....
How to do it without reload the html page?
Thanks.
You could use jquery to send the ajax request and server could send the response with html content.
For example,
Server: When server receives the ajax request. This would return the html content i.e. a template which could be rendered to the client via ajax
def update_html_on_client(request):
language = request.GET.get('language', None)
#for selected language do something
cal_1 = ...
return render_to_response('my_template.html', {'cal':cal_1}, content_instance = template.RequestContent(request))
Template: This is example of ajax function you would use to generate ajax request. You can select the div in which you can populate the html response returned by the server.
function getServerResponse(){
$.ajax({
url: 'your_url_here',
data: {language:'German'},
dataType:'html'
success : function(data, status, xhr){
$('#server_response').html(data);
}
});
}
Because your templates are rendered on the server, your best bet is to simply reload the page (which re-renders the page with your newly selected language).
An alternative to using ajax would be to store the language in a cookie, that way you don't have to maintain state on the client. Either way, the reload is still necessary.
You could investigate client side templating. Handlebars is a good choice.

Categories

Resources