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.
Related
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
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)
i have a webpage that loads certain JavaScript packages.
www.mySite.com
If i enter JavaScript commands in the browser console, i am able to interact with them.
Lets take
alert('5')
as a simple example.
I would like the same JavaScript calls to be executed without the browser console but through a specific URL like:
www.mySite.com/?value=5
so that this leads to an execution of my JavaScript commands?
Without the Page beeing reloaded/refreshed but staying in the actual state.
My approach was to catch the extended URL in my Django View and execute the JavaScript command.
View:
class ShowPage(View):
def get(self, request, caseId):
value = request.GET.get('value', '')
if(value is not ''):
// execute JavaScript here...
return HttpResponse("<script>alert(" + value + ")</script>")
else:
...
return render(request, 'template.html', context)
But this leads to a loss of my page where i entered the URL.
Does anyone has an idea how to preserve the actual Browser content?
So that it is possible to call the loaded Javascript packages?
Another idea was to call JavaScript through Ajax. But how do i map a URL in Django to a Ajax request?
Your current code is problematic on many levels, particularly because it allows the user to execute arbitrary JS on your page. This is called a Cross-site Scripting (XSS) attack.
Another issue is that you seem to want to add a GET parameter without "changing the state" of the page. Here you must remember that a GET request is, by definition, a communication between the client and server. You can artificially change what the URL looks like using JS, but you cannot submit a GET request on the same page without reloading it.
This is why you certainly want to use AJAX, which allows you to fetch the contents from another page and return them to the current page in the background. Usually this is done by creating a view that returns a JsonResponse (in Django 1.7+) (see Creating a JSON response using Django and Python).
A simplified example would be to encode a view that simply displays some text. You could then retrieve this text using AJAX (I recommend the jQuery for this--it's simple and well-documented) and do whatever you want with it, including alert it.
Try to use a '#':
www.mySite.com#command
This doesn't reload the site.
Maybe this helps too:
url: https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
url: Get current URL in web browser
'#': http://www.w3schools.com/html/html_links.asp
EDIT:
use 'eval()' to execute the input:
http://www.w3schools.com/jsref/jsref_eval.asp
I don't know if i'm doing this the right way, but in my django application I have javascript helping out the login page. I made an ajax rest api on my django server (with that whole csrv authentication).
Now, I want to redirect the user when the javascript successfully posts an ajax call to the server. I figured it might be easy to return a json with a 'success': true and a 'url': , but I can't figure out a nice way to get that url string. I know django is strict on only typing out the url in one spot and referencing it from the urls.py.
My question is: How do I get that url string to send to the client-side? OR if there is a better way to do this, how do I go about that?
(The reason I'm not using forms is because I need to filter out certain signup things that I cannot filter from the usual way of putting {{ LoginForm }} into the template)
Take a look at the reverse function
reverse('url-name') will return the path to your view named url-name
I'm trying my hand at unobtrusive JS, using JQuery in my Ruby On Rails app.
After the user fills out a form, the client-side JQuery code calls:
$.post("/premises", ui.form)
I can see the POST hit the server, and I can see the server emit a redirect notice to http://localhost:3000/users/42 complete with the data to be displayed.
But the browser page doesn't change. This doesn't really surprise me -- the whole point of client-side javascript is to control what gets updated -- I get that. But in this case, I'd like to honor whatever the server replies with.
I tried extending the call to post() based on How to manage a redirect request after a jQuery Ajax call:
$.post("/premises",
ui.item,
function(data, textStatus) {
if (data.redirect) {
// data.redirect contains the string URL to redirect to
window.location.href = data.redirect;
} else {
// data.form contains the HTML for the replacement form
$("#myform").replaceWith(data.form);
}
});
... but (among other problems) data.redirect is undefined. I suspect the real answer is simple, right? Looking forward to it!
The post you refer to uses JSON as return value and it is constructing that json on server side. it means if there is redirect your data object would look like
{redirect:'redirecturl.html'}
and if it is not redirect then data object would be like
{form:html-string-for-form}
now job is to construct json object accordingly on server side
The server is saying that the data you want to process with JavaScript is available at a different URL, not that the browser should load a new document into the top level frame. Sending the browser to the URL where it was told the data it was requesting with JS is wouldn't be honouring the redirect.
If you want to do that, then the server should respond with data (in the body of the response) that the JavaScript interprets as a reason to assign a new value to location.
data.redirect is probably undefined because you're not specifying it on the server side. In the answer you linked to the point was to have the server always respond with 200 regardless of the outcome, and then the JSON body it sends back determines how the client reacts. So, on the server side you'd want to respond with {"redirect" : "/where/to/go"}