Django + Ajax error in returning data - javascript

I have a model called Item and I'm trying to create Items with Ajax, everything looks to be working ok, but I'm getting and error at the end of the process, in the success function in Ajax. I have been reading a lot of answers to questions like this here in StackOverflow but I couldnt make it work:
This is my model:
PRIORITY_CHOICES = (
(1, 'Low'),
(2, 'Normal'),
(3, 'High'),
)
class Item(models.Model):
name = models.CharField(max_length=60)
description = models.TextField(max_length=1000)
created = models.DateTimeField(auto_now_add=True)
priority = models.IntegerField(choices=PRIORITY_CHOICES, default=1)
done = models.BooleanField(default=False)
meeting = models.ForeignKey(Meeting)
def __str__(self):
return self.name
This is my view, whichs is working Ok and saving the data into de database:
from .forms import AddItemForm
from .utils import render_to_json_response
class AjaxFormResponseMixin(object):
def form_invalid(self, form):
return render_to_json_response(form.errors, status=400)
def form_valid(self, form):
# save
self.object = form.save()
# initialize an empty context
context = {}
# return the context as json
return render_to_json_response(self.get_context_data(context))
class AjaxItemCreateView(AjaxFormResponseMixin, CreateView):
form_class = AddItemForm
def get_context_data(self, context):
context['success'] = True
context['name'] = self.object.name
context['description'] = self.object.description
return context
as you can see, I'm using a custom shortcut called render_to_json_response in order to parse data in Json
this is the code of the shortcut (Please notice that I'm printing the context, in order to verify the data):
from django.http import JsonResponse
def render_to_json_response(context, **response_kwargs):
print (context)
return JsonResponse(context)
(if you're wondering why I'm using this simple shortcut it's because previously I was trying to return the response with HttpResponse and specifying content_type="application/json", but it also wasn't working)
This is my ajax code:
function AddItem(event){
var csrftoken = getCookie('csrftoken');
var item_name = $('#item-name').val();
var item_desription = $('#item-description').val();
var item_priority = $('#item-priority').val();
var item_meeting_pk = $('#item-meeting-pk').val();
var url = "/item/add/";
$.ajax({
type: "POST",
url: url,
data: {
'name': item_name,
'description': item_desription,
'priority': item_priority,
'meeting': item_meeting_pk ,
'csrfmiddlewaretoken': csrftoken
},
success: function(data){
alert("success");
alert(data);
},
complete: function(data){
alert("completed");
alert(JSON.stringify(data));
}
});
}
and, finally, this is the form that calls the AddItem() function:
<form>
{% csrf_token %}
<input type="text" placeholder="Nombre del item" id='item-name'/>
<input type="text" placeholder="Descripción del item" id='item-description'/>
<select id="item-priority" name="provider" class="form-control">
<option value="1">Baja</option>
<option value="2">Normal</option>
<option value="3">Alta</option>
</select>
<input type='hidden' id='item-meeting-pk' value='{{ meeting.pk }}'>
<button onclick='AddItem()' class="button-blue" >Agregar</button>
</form>
When I submit the form, everything goes fine, and in my django shell I can see that the post request is returning 200 and the data is printing ok:
{'name': 'asdkkasd', 'description': 'sdksdksjd', 'success': True}
[29/Aug/2015 08:34:22]"POST /item/add/ HTTP/1.1" 200 65
in the ajax function I have javascript alerts in both success and complete, but only the complete's one is executing and this is what I'm getting with the execution of alert(JSON.stringify(data));:
{"readyState": 0, "responseText":"", "status":0, "statusText": "error"}
I hope you can help me, thank you :)

Your form is almost certainly invalid; you're returning a 400 status in that case from form_invalid, which triggers jQuery to call the failure function if there is one, rather than success.
Unfortunately, you can't use proper RESTful status codes in this kind of situation. An invalid form submission should still return a 200.

There is a difference between success and complete function of the ajax function that you are using...
success
It gets called on a response of 200 (OK).
complete
This will get called always , well as the name suggests the request did succeed, even if was a failure on the server side or OK response. It just succeeded (ie: landed your server and brought something back to offer to your client(browser,mobile whatever).So that's complete method for.
You can do away with this method and can use only success if not needed otherwise.
For more info. Read here
FYI :
The readystate output you showed says 0 , hence the request isn't initialized.It should be 4 for the request to be complete.

Related

Ajax returning empty string in Django view

I am developing a web application through Django and I want to get information from my javascript to a view of Django in order to access to the database.
I am using an ajax call as this post shows.
I am calling the js in html by an onclick event :
sortedTracks.html
...
<form action="{% url 'modelReco:sortVideo' video.id %}">
<input type="submit" value="Validate" onclick="ajaxPost()" />
</form>
...
clickDetection.js
//defined here
var tracksSelected = [];
//function that fill tracksSelected
function tagTrack(track_num){
if(tracksSelected.includes(track_num)){
var index = tracksSelected.indexOf(track_num);
tracksSelected.splice(index, 1);
}else{
tracksSelected.push(track_num);
}};
//ajax function
function ajaxPost(){
$.ajax({
method: 'POST',
url: '/modelReco/sortedTracks',
data: {'tracksSelected': tracksSelected},
success: function (data) {
//this gets called when server returns an OK response
alert("it worked! ");
},
error: function (data) {
alert("it didnt work");
}
});
};
So the information I want to transfer is tracksSelected and is an array of int like [21,150,80]
views.py
def sortedTracks(request):
if request.is_ajax():
#do something
print(request)
request_data = request.POST
print(request_data)
return HttpResponse("OK")
The ajax post works well but the answer I get is only an empty Query Dict like this :
<QueryDict: {}>
And if I print the request I get :
<WSGIRequest: GET '/modelReco/sortedTracks/?tracksSelected%5B%5D=25&tracksSelected%5B%5D=27&tracksSelected%5B%5D=29'>
I have also tried to change to request_data=request.GET but I get a weird result where data is now in tracksSelected[]
I've tried to know why if I was doing request_data=request.GET, I get the data like this tracksSelected[] and get only the last element of it.
And I found a way to avoid to have an array in my data (tracksSelected) on this link
This enables me to have :
in views.py
def sortedTracks(request):
if request.is_ajax():
#do something
print(request)
request_data = request.GET.getlist("tracksSelected")[0].split(",")
print(request_data)
and in clickDetection.js
function ajaxPost(){
tracksSelected = tracksSelected.join();
$.ajax({
method: 'POST',
url: '/modelReco/sortedTracks',
data: {'tracksSelected': tracksSelected},
success: function (data) {
//this gets called when server returns an OK response
alert("it worked! ");
},
error: function (data) {
alert("it didnt work");
}
});
};
This little trick works and I am able to get the array data like this,
print(request_data) returns my array such as [21,25,27]
Thank you for helping me !
According to me to access the data which is sent in the ajax request can be directly accessed .
For Example:
def sortedTracks(request):
if request.method == 'POST':
usersV = request.POST.get('tracksSelected')[0]
for users in usersV:
print users
return HttpResponse("Success")
else:
return HttpResponse("Error")
The correct syntax is data: {tracksSelected: tracksSelected},

How could i display search result based on filtered value provided by user?

I have developed filter system where it provides 3 options such as property type, number of rooms, and maximum price. Every time they select filter options the user will get their search result instantly. For example, if a user has selected property type of Apartment and number of rooms as 4 and maximum price of 12000 then the user will get those rents whose property type is apartment with 4 rooms of 12000 mark. I developed the front-end part with React.js and could fetch user selected data successfully. I have also passed data to ajax but I have no idea how should I display the search results based on filtered value provided by user with no page loading.
Ajax code
$.ajax({
type: 'GET',
url: '/filter/space/',
data{property:propertySelectedValue, room:roomSelectedValue, price:maxPrice},
success: function(data){
console.log(data['fields']);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.error("Status: " + textStatus); alert("Error: " + errorThrown);
},
});
Views.py
class FilterSpace(View):
def get(self,request,*args,**kwargs):
property = request.GET.get('property',None)
room = request.GET.get('room', None)
price = request.GET.get('price', None)
rental = Rental.objects.all()
if room:
rental = rental.filter(room=room)
print('rental',rental)
if price:
rental = rental.filter(price__lte=price)
if property:
rental = rental.filter(property=property)
rental_json = serializers.serialize('json',rental)
print('rental_json',rental_json)
return HttpResponse(rental_json,content_type="application/json")
One thing you might consider doing is rendering the html to a string (django - render_to_string not working) on the server side and send that back in an ajax response along with the data. then replace the html where the list is contained with that rendered by the server.
Django:
def get_list(request, *args, **kwargs):
items = Items.objects.filter(...)
html = ""
items = [] # actual data
context = {
"item_list": items,
...
}
for item in items:
html = html + render_to_string(list_html_template, context, context_instance=RequestContext(request))
items.append(item.to_json()) # You have to define this if you want it.
return JsonResponse({
"list_html": html,
"items_data": itmes
})
Template (list_html_template):
{% for item in item_list %}
<!-- render item here... -->
{% endfor %}
Javascript:
$.ajax({
url: "url_for_get_list_view",
dataType: "json",
...
success: function(json) {
$(list_container).html(json.list_html); // Will replace any current html in this container (i.e. refresh the list).
/* You can also do stuff with json.items_data if you want. */
}
});
for efficiency in the python you should find the way to filter once with all the parameters instead of filter the filtered of the filtered, but this is not essential to see result.
inside success: function(data){ you should use jQuery to put data into the page, you might start with something like
function data2html(data) {
...// use .map and .join
}
$("#divid").append(data2html(data))
You can clear up your view by doing something like this:
class MyView(View):
def get(self, request):
results = Rental.objects.filter(**request.GET)
return serializers.serialize('json', results)
and when you get the data back in your AJAX request, in the success part just clear your table and iterate over the results and append rows to the now empty table with your data.
In my opinion, its clearer to have the logic and rendering taking place in django using AJAX to retrieve and place the rendered html. Here is a sketch of the code
Here is the view that passes the set of rentals to an html template
def ajax_rental_search(request):
search_text = 'missing'
if request.method == "GET":
search_text = request.GET.get("search_text", "missing")
# DEBUG: THIS CAN CHECK THE CONNECTION
# return HttpResponse('SERVER RESPONSE: search_text: ' + search_text)
if search_text != 'missing':
rentals = Rental.objects # add filters etc.
context = {
"rentals": rentals
}
return render(request, "rentals_search_response.html", context)
Here is the key part, the jquery, ajax request:
function rentalSearch() {
const search_text = content_search_input');
$.ajax({
type: "GET",
url: < rental_search_url >,
data: {
'search_text': search_text,
},
success: function (serverResponse_data) {
// console.log('search success: ' + serverResponse_data);
$('#rentals_content').html(serverResponse_data);
// rentals_content is an existing div on page
},
error: function (serverResponse_data) {
console.log('error:' + serverResponse_data)
}
});
}
Then you can style the displayed rentals as you wish knowing that they are all going to passed to the sub template.
Thats it

Use POST and GET in the same view django

On clicking a button (send_net), I want to send the text stored in the input "text" from a django template to a view and to the url associated with that view.
The associated html:
<div class="search_box">
<form id="target" action="." method="post">{% csrf_token %}
<input type="text" id = "sbox" placeholder="Search...">
</form>
</div>
I send the variable to the view using a POST request:
$(document).ready(function(e){
$('#send_net').click(function(e){
var query = document.getElementById("sbox").value;
var d = {'query':query};
$.ajax( link, {
type: "POST",
data: d,
success: function(data) {
alert('call back');
},
error: function(jqXHR, textStatus, errorThrown) {
alert("Error, status = " + textStatus + ", " +
"error thrown: " + errorThrown
);
}
});
});
});
views.py
def create_network(request):
c={}
c.update(csrf(request))
r=[]
if request.method=='POST':
if 'query' in request.POST:
query = request.POST['query']
r.append({'id':1, 'label':query})
venues = Venue.objects.filter(title__contains="Life")
for venue in venues:
d={}
d['id'] = venue.id
d['label'] = venue.title
r.append(d)
data = json.dumps(r)
edges = [{'from':15505, 'to':19092}]
data_e = json.dumps(edges)
con = RequestContext(request, {"nodes":data, "edges":data_e})
return render_to_response('quir/network.html', c, con)
However r never has the '{'id':1, 'label':query}' because the subsequent GET request wipes it clean. How do I retain the query value in 'r'? I'm relatively new to Django and javascript so sorry if this is elementary.
Thanks very much.
You could use Class-based views and define a method for GET and another one for POST:
class CreateNetwork(View): # Extend from the view you need
c = {}
r = []
def get(self, request, *args, **kwargs):
# This code will be executen in a GET request
# here you can access c or r with self
self.c.update(csrf(request)) # this is just an example
...
def post(self, request, *args, **kwargs):
# This code will be executed in a POST request
self.r.append(...)
You need to use
if request.method == 'POST':
pass # Your code
else:
pass # For GET
When you want to process both POST and GET, you need to specify it like so.

Using AJAX POST from javascript to Rails 4 controller with Strong parameter

I'm newbie with Rails
My purpose is insert song_id and title which received from Javascript via AJAX POST into Database (MySQL)
In my javascript file
var song_id = "23f4";
var title = "test";
$( document ).ready( function() {
jQuery.ajax({
url: 'create',
data: "song_id=" + song_id + "&title=" + title,
type: "POST",
success: function(data) {
alert("Successful");
},
failure: function() {
alert("Unsuccessful");
}
});
} );
In my editor_controller.rb
class EditorController < ApplicationController
def new
#song = Song.new
end
def create
logger.debug("#{params[:song_id]}")
logger.debug("#{params[:title]}")
#song = Song.new(song_params)
if #song.save
redirect_to root_path
else
flash[:notice_song_failed] = true
redirect_to root_path
end
end
private
def song_params
params.require(:song).permit(:song_id, :title)
end
The problem is when I running the Rails app with this code, the Console notices me that
ActionController::ParameterMissing at /editor/create
param is missing or the value is empty: song
I'm trying to use
private
def song_params
params.require(:song).permit(params[:song_id], params[:title])
end
but it doesn't work and notices me the same, moreover in the terminal log told me below
Started POST "/editor/create" for ::1 at 2015-04-01 01:07:23 +0700
Processing by EditorController#create as /
Parameters: {"song_id"=>"23f4", "title"=>"test"}
23f4
test
Completed 400 Bad Request in 1ms
Do I missed something in my code, Thanks for Advance.
You are not sending a song parameter at all. It looks like you need to update the data line in the jQuery.ajax call to include the song parameter like so:
data: {song: {song_id: song_id, title: title}}
This:
params.require(:song).permit(params[:song_id], params[:title])
is saying "require the 'song' parameter, and allow 'song_id' and 'title' through. If you don't pass a song parameter, you'll get a bad request.
You can either:
Change that line of code to remove the require on 'song'
or
Like #infused says, change your ajax call to send a song JSON object.

Convert checkbox 'on' to Boolean before posting to Django view

I am building a Django app that has a main dashboard with a bunch of on/off toggles. My goal would be to allow the user to toggle their settings on or off and have their changes automatically saved to the database.
So I followed this tutorial to leverage Ajax form submissions in my Django app so that the user would not have to reload the page. The problem that I am having (I think) is that the checkbox values are being POSTed to my Django views as 'on' whereas they should be POSTed as 'True'.
I think that this is the cause of the error, because I see this in my error logs:
Exception Type: IntegrityError at /update_usersettings/
Exception Value: dataplan_usersettings.normalize_person_name_proper may not be NULL
...
POST:
id_normalize_person_name_proper = u'on'
id_normalize_company_name_proper = u'on'
My existing JavaScript and Django views.py are here: https://gist.github.com/joefusaro/25b6221536291c1ba0d1
Update:
I've added the relevant Django template and forms code here. Not that I am using widget_tweaks for form rendering. The form renders like so:
<form action="/update_usersettings/" method="POST" id="usersettings_form">
<input checked="checked" class="bootstrap-switch-default" id="id_normalize_person_name_proper" name="bootstrap-switch" type="checkbox" />
<input checked="checked" class="bootstrap-switch-default" id="id_normalize_company_name_proper" name="bootstrap-switch" type="checkbox" />
<input type="submit" value="Post">
FINAL UPDATE
Thanks to Animesh for a great starting point. Here is the final Ajax code required. Special thanks to Victor K. for his help figuring this out!
Here is the final Ajax code:
$(function() {
// Submit post on submit
$('#usersettings_form').on('submit', function(event){
event.preventDefault();
console.log("Form submitted...") // sanity check
save_usersettings();
});
$('input[type="checkbox"]').on('switchChange.bootstrapSwitch', function(event, state) {
$('#usersettings_form').submit();
});
// AJAX for posting.
function get_post_data() {
var data = {};
$('input:checkbox').each(function () {
var $this = $(this);
var id = $this.attr('id');
data[id.replace('id_', '')] = $this.is(':checked');
});
return data;
}
function save_usersettings() {
console.log("Saving user settings...") // sanity check
$.ajax({
url : "update_usersettings/", // the endpoint
type : "POST", // http method
data : get_post_data(),
// handle a successful response
success : function(json) {
console.log(json); // log the returned json to the console
// $("#talk").prepend("<li><strong>"+json.text+"</strong> - <em> "+json.author+"</em> - <span> "+json.created+
// "</span> - <a id='delete-post-"+json.postpk+"'>delete me</a></li>");
console.log("Successfully saved user settings."); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
// $('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
// " <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
};
And here is the final views.py:
class UpdateUserSettings(LoginRequiredMixin, UpdateView):
model = UserSettings
form = UserSettingsForm
def post(self, request, *args, **kwargs):
if request.method=='POST':
response_data = {}
form = UserSettingsForm({})
us = UserSettings.objects.get(user=1)
VALUE_MAP = {
'false': False,
'true': True
}
for name, field in form.fields.items():
if isinstance(field, BooleanField):
if request.POST.get(name):
if request.POST[name] in VALUE_MAP.keys():
setattr(
us,
name,
VALUE_MAP[request.POST[name]]
)
us.save()
response_data['result'] = 'Update successful!'
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({"nothing to see": "this isn't happening"}),
content_type="application/json"
)
You can handle this inside the view.
CHECKBOX_MAPPING = {'on':True,
'off':False,}
class UpdateUserSettings(LoginRequiredMixin, View):
model = UserSettings
def post(self,request,*args,**kwargs):
normalize_person_name_proper = CHECKBOX_MAPPING.get(request.POST.get('normalize_person_name_proper'))
You can do this for all the fields you are supposed to receive in checkboxes from the user.
Also, one thing to note here is that you need not use request.method=='POST'check inside the post method of a class based generic view. The method will be called only when the request is POST.What you are looking for is if request.is_ajax():
Hope this helps.

Categories

Resources