Forgive me for stupid questions, but I do not really understand how such relationships work in the Web-development.
I have views.py:
As you can see there is a connection to the api and the information I need is parsed.
Then in my template I have a listener that shows when the user reached the bottom of the page:
As you can see at the bottom of the template i have ajax block where I again connect to api
But now the most important question is this the right way?
Do I need to connect json and fill my arrays and elements in the ajax block one time more? BUT It's all done in views.py.In general, is it realistic to call def main(request) from ajax all the time and append all my arrays and elements automatically? I need like smth this :
$(window).scroll(function () {
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
$.ajax({
url: "{% url 'main' %}",//my request which appends all my arrays automatically
type: "GET",
success: function () {
},
error: function () {
});
Sorry for such questions but I do not understand how such bundles work
As for the counter of connected pages, I'll deal with this later, I need information now in which direction to move in general
It's not a good way. Generally, Django view does not have anything to do with it. You should directly call the URL from ajax and parse the answer in your JS, on the page itself. However, if it is necessary to process the response from that URL in some way, then you should create a separated view that will process the response and return the corresponding JSON as a response.
So the first view only needs to have a template response, and your ajax script on the page should call another view and take over from JSON. This second view sends the request to that remote URL and processes it, then returns JSON as a response.
For this other view, I recommend Django Rest Framework, but this is not necessary if it's a simple feature.
Related
I have a page on my website where user can upload a xlsx file using ajax, on backend I read the file, do a little processing and start inserting its rows one by one in my database. If the files uploaded by the user gets quite large, entering new values in the database can take a while. Therefore I want to give user real-time progress update on their screen, eg. -
Found 100 rows of data
Interesting 1/100.
Interesting 2/100.
...
Interesting 100/100.
Done.
My View:
import pandas as pd
def myView(self, request):
"""Handle POST requests, save all data provided in excel file."""
excel_file = request.FILES.get('excel_one')
excel_df = pd.read_excel(excel_file)
data_format = ['Option_1', 'Option_2', 'Option_3', 'Option_4',]
try:
formatted_df = excel_df[data_format]
except KeyError as error:
return JsonResponse({'success': False, 'message': str(error), })
# forloop to create model objects
for i, v in formatted_df.iterrows():
# do a lot of data validating and stuff first
MyModels.objects.create(arguments)
print(f'Created object {i+1}/{len(formatted_df)}!' # Want to to be sent to html page in real time
return JsonResponse({'success': True, })
I am making an ajax request like this:
$.ajax({ // variables url, data, etc. contain the expected stuff
async: false,
url: url,
method: "POST",
data: data,
success: function(d){
if(data.success){
console.log(d);
}
else{
$('.log').append('<p><b>Error:</b> '+ d.message +'</p>')
}
},
cache: false,
contentType: false,
processData: false
});
Saving data in database and everything else is working as expected but I just can't figure out how to send real-time updates to ajax. One possible solution I can think of is to implement web sockets instead of normal http requests, but I am in a little hurry so is there any way to do it with simple js and django.
If you don't want to resort to WebSocket, you can try:
the quick and dirty way: have your JS poll another API view to check the status
Have you heard of StreamingHttpResponse? I've never used it, but might be worth a try. You can see an example here.
Celery will help here like anything.
Just write a function for our time-consuming task, set this up as a celery task
Return a process id or file whatever immediately as a response for the first API
Poll on a second API from ur ajax with this id, get the expected result on this API
Please note: Don't keep any HTTP request open for more than a specific period of time, this will impact the performance seriously.
I'm using Flask with Flask-Security (specifically Flask-WTF regarding my csrf issue) to "ease" the process of register/loggin users (not easy so far). I'm using BackboneJS on the front-end, therefore I kind of hacked the original way to use Flask-WTF. Indeed, I make an AJAX GET request on /register to get the register page (generated by Flask-Security) and I put the resulting HTML in a modal.
render: function () {
var self = this;
$.ajax({
type: 'GET',
url: Config.constants.serverGateway + "/register"
}).done(function(result){
console.log("get register done", result);
var html = self.template({ config: Config, form: result });
self.$el.html(html);
}).fail(function(error){
console.log("Could not get register token", error);
var html = this.errorTemplate({ config: Config });
self.$el.html(html);
});
return this;
}
This way I have the generated csrf, and when I POST the registration data, I send the right csrf along the user data (email and password).
submit: function () {
console.log("submit");
var self = this;
var formData = this.$el.find('form').serialize();
$.ajax({
type: 'POST',
url: Config.constants.serverGateway + "/register",
data: formData,
dataType: 'json'
}).done(function(result){
self.trigger('close');
}).fail(function(error){
console.log("Could not submit register data", error);
});
}
On the server-side, I can debug my python code to see that the csrf_token which has been generated when I requested the register page has disappeared from the session object, therefore leading to the generation of a new one, which of course didn't match the one I send with my form. The session is still the same though, as the _id is the same during the GET and the POST.
You can see the code in flask_wtf/csrf.py::generate_csrf(), which is called when creating the form object in the ::register function from flask_security/views.py
if 'csrf_token' not in session:
session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()
It results in a CSRF TOKEN MISSING error.
An additionnal information, is that my front-end and back-end are delivered by the same server, as they have a different port number.
Last, when I use an href on front-end and display the page returned by the server on the 'GET' request, submitting the form works well. I just liked to display this registration form in a modal.
Thanks for your help
Okay, I finally figured out the solution to my problem. I feel like a noob (which I am).
The problem lied in the session credentials which were not sent to the server with the requests, so that the server coudldn't access the session cookie.
I found the solution in the following tutorial: http://backbonetutorials.com/cross-domain-sessions/
To send it, i added the following lines in my Backbone router initialize function:
// Use withCredentials to send the server cookies
// The server must allow this through response headers
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.xhrFields = {
withCredentials: true
};
});
This makes all AJAX requests include the withCredentials = true. On the server-side, I had to set Access-Control-Allow-Credentials:true. Since I'm using flask-cors, it is done with [supports_credentials=True][2] when creating the CORS object.
(I'm answering here since I can't comment)
#junnytony Yes I have the token in my modal and I send it in my POSt request. When I debug the Flask application, I can see the toekn I sent with my POST request, the problem is that it should be compared to the one in the session to be validated, but the one in the session has disappearred, so the flask-wtf lib generates a new one, which results in a failure when comparing with the one I sent.
On GAE (Python) I'm trying to send a GET request from local javascript and on receipt of the request redirect to another page. This is my code:
Local Javascript sending the POST:
$.get("/editor");
The Python on GAE
class Editor(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
app = webapp2.WSGIApplication([('/', StartScreen), ('/editor', Editor)],
debug=True)
I can type in the url /editor in the url bar and it does take me there. Why does my javascript GET request not activate the Editor handler and open /editor?
I am not sure if I understand the problem, but still give it a try:
The current way to use jQuery.get() should call the server but throw away the response, so you will see nothing of it in the browser.
You want at least to do:
$.get("/editor", function(response) {
document.location.href = 'another page';
});
where another page is where you want to redirect to. Then this still throws away what you content you get from the server. (response will be some HTML ... I am not sure how you want to get a location from that.) So I wonder if a simple HTML-link would just do what you want.
I'm writing an AJAX function that requests data from my JSON Python webservice. My AJAX request looks like:
url = "http://localhost:8001/blah"
$.ajax({
url: url,
type: 'get',
dataType: 'jsonp',
success: function(data) {
console.log('hi')
}
});
For now, my python web service has a function that handles the request to '/blah' that has the following return statement:
return json.dumps({'a':1, 'b':2 })
My AJAX function is not successfully retrieving a response from my Python Webservice, but I don't get any errors in Firebug. What is my webservice or javascript doing wrong?
What happens when you use Jquery's JSONP datatype, is that a callback function name is sent as a GET param as part of your URL, so you're actually querying something like "http://localhost:8001/blah?callback=json125348274839".
Your response from your web server should look like this:
return "%s({'a':1, 'b':2 })" % _GET_PARAMS('callback')
so your web server will return somthing like "json125348274839({'a':1, 'b':2 })"
Hope that helps!
Zack got it. My javascript was correct. I changed my python return statement to the following:
callback = request.args.get('callback')
return '{0}({1})'.format(callback, {'a':1, 'b':2})
Turn on (or add) logging in your Python web service. Inspect your web server logs... are you receiving the request from your javascript client? Is your web server logging that it is returning a response?
Possibly it depends on the framework that you are using. Is it as simple as returning a string from the handler function? Perhaps the handler is supposed to return a list of strings and, because it is not getting a list, it is returning nothing to the client. Look in your web server logs for errors.
You forgot closing quote and semicolon in the first line =)
If it is not helps, check following:
List item
What are you using as python service? Django, flask, something else? Maybe you can provide provide python code?
Also, look at the 'Net' Firebug's tab and, after ensure that request to 'url' is actually handled (not returned 404 or 50x codes, but 200), check 'Response' sub-tab.
Hope this helps!
Alright, I'm working with a RESTful backend on my project, and submitting data via jquery.
I must say the werkzeug debugger is excellent for debugging specially when you're a terrible python programmer as me. You throw an exception on purpose where you want to investigate, and inspect the code and variables using the html the debugger rendered.
However when you send a post request instead of a get, if you throw an exception on the backend code, of course, the browser won't render the response text.
Is there any technique I can use to render the response text, considering it has javascript and everything?
I'm trying different things such as trying to inject the response text into a popup window, like:
$.postJSON = function(url, data, callback, error_callback) {
return jQuery.ajax({
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': JSON.stringify(data),
'dataType': 'json',
'success': callback,
'error': error_callback
});
};
$.postJSON('/the_uri', {'foo': 'bar'},
function(response) {
var a = 0;
},
function(response) {
var html = response.responseText;
var my_window = window.open('', 'mywindow1', 'width=350,height=150');
$(my_window.document).find('html').html(html);
});
});
But this won't take care of the javascript very well.
Does anyone have any suggestion?
Your approach was nearly correct. I am using the following code to open the response text in a new window (not specific to Werkzeug or Flask at all):
var w = window.open('', 'debug_stuff', 'width=540,height=150');
w.document.open();
w.document.write(response.responseText);
w.document.close();
The last line is the most important. Without it, the code would behave as yours -- it would not execute any JavaScript, because the browser doesn't know the DOM has been fully loaded.
Not javascript, but have you tried to use Firebug, you can use the option for viewing the response in a new tab (Open Response in New Tab).
If you're ready to make some changes on both the client and the server code, you can try this. In your error callback you would re-send the JSON data but as a synchonous form submission. You would create the form using jQuery, give it an input tag and put your JSON in that and submit the form. Something like:
$('<form method="post" style="display:none;">')
.attr('action', 'xxx')
.append(
$('<input>').val(JSON.stringify(data))
).appendTo('body')
.submit();
On the server-side, you would have to accept JSON the regular way when the request's content type is application/json and as form data, eg:
json_string = request.form.get('__json')
if json_string:
data = json.loads(json_string)
I have never tried this but I know the problem you're having and it can waste a lot of time. If you try it I'd like to know how it works out.
Markus' answer works perfectly. thanks so much! this saved me so much hassle.
also consider assigning your handlers to a jqxhr object
http://api.jquery.com/jQuery.post/#jqxhr-object
var jqxhr = $.post(...)
then you would write to your new window
w.document.write(jqxhr.responseText);