interaction Django and Ajax - django

I'm trying to send data to the server and use with AJAX
function stats(e){
jQuery.ajax({
type: "POST",
url:"stats",
data:{'csrfmiddlewaretoken': document.getElementsByName('csrfmiddlewaretoken')[0].value,
'test':{}},
success: function(data) {alert("Congratulations!"+data);},
error: function(data) {
alert("Please report this error: "+data.responseText);}
});
}
function in views.py:
def stats(request):
if request.is_ajax():
if request.user.is_authenticated():
if request.POST:
return HttpResponse(request.POST['test'])
else:
return HttpResponse("post_no_exists")
else:
return HttpResponse("no authenticate")
else:
raise Http404
Django raise MultiValueDictKeyError 'key "test" not found in QueryDict'.
When I change "test":{} -> "test":1 it succeds.
Whats my error?

Here:
...
data: {
'csrfmiddlewaretoken': ...,
'test': {}
}
...
You're trying to send an empty object literal as part of the POST request. jQuery can't figure out what value to send for that (empty object? what would that even mean?), so it simply doesn't send the test parameter at all. Thus, on the server side, trying to access request.POST['test'] throws a KeyError.
When you change the test to a different literal (in this case a number), jQuery can easily encode and send that as the value.

You need return answer as json
payload = {'answer': 'post_no_exists'}
return HttpResponse(json.dumps(payload, cls=LazyEncoder), content_type='application/json')
in js
alert("Congratulations!"+data.answer);

Related

Cannot get values from request in Django - Empty QueryDict

I’m new to ViewSets and am trying to get the values sent from the front-end fetch method to Django’s request object in the create function. I don’t know whether it’s just a simple syntax error or whether the data isn’t being sent properly from the front-end, but I think it’s a back-end issue.
The stringified data in the post method seems to log correctly at the front-end like with this test:
{"title":"test","type":"landing","slug":"","notes":""}
Printing variables in the ViewSet’s create function however shows these:
print(request.POST["title"]) # fails with keyerror: 'title' MultiValueDictKeyError(key) django.utils.datastructures.MultiValueDictKeyError: 'title'
print(request["title"]) # fails with TypeError: 'Request' object is not subscriptable
print(request.POST.get("title", “test”)) # fails as print test
print(request.POST.get("title")) # fails as it just returns None
print(request.get("title")) # fails with AttributeError: 'WSGIRequest' object has no attribute 'get'
print(self.request.query_params.get("title", None)) # prints None
print(self.request.query_params) # prints empty QueryDict: <QueryDict: {}>
Here’s the create function:
class PagesViewSet(viewsets.ViewSet):
def create(self, request):
# printing went here
page = Page.objects.create(
title="testing", type="other", slug="test-slug", notes="test notes"
)
serializer = PageSerializer(page)
return Response(serializer.data)
I’ve just chucked in demo data inside the page create method to ensure it works, which it does, and now want to use the real data which should be in the request.
Does anyone know what might be the issue here?
For visibility, here’s the front-end API-request function:
const createPage = async (data: CreatePageFormInputs) => {
console.log('stringified: ', JSON.stringify(data)); // logs correctly
const res = await fetchCreatePage('http://localhost:8000/api/pages/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
};
Maybe irrelevant but in case you're wondering what fetchCreatePage is, it's just this part of a custom react hook:
const fetchCreatePage: FetchDataFn = async (url, options?) => {
const setFailed = () => {
setFetchError(true);
setLoading(false);
};
const setSuccess = (data: any) => {
setData(data);
setLoading(false);
};
try {
setLoading(true);
const res = await fetch(url, options);
if (!res.ok) {
console.log('Error detected. Returning...');
setFailed();
return;
}
if (res.status === 204) {
setSuccess({
success: true,
info: 'Item successfully deleted',
});
return;
}
const data = await res.json();
setSuccess(data);
} catch (e) {
setFailed();
}
}
I assume the POST method is correct. Any help would be appreciated, thanks.
You wrote the data as body of the request in a JSON format. You thus should decode the JSON format to a dictionary with:
import json
data = json.loads(request.body)
print(data['title'])
If you are using a request from the Django REST framework, you work with request.data:
import json
print(request.data['title'])
request.data will look for POST parameters and a JSON body.

Navigating to different page instead of Ajax call

I am trying to save a form via ajax as I don't want to reload the page. It is working not completely but it is updating the data except the image or video or any upload file we give.
but after updating it is coming back to the ajax page but the url is diiferent and success message is coming on that page.
I am sharing some of the logic but if more information is required, please let me know .
js code :
$(document).ready(function() {
$('#contentdataform').submit(function(e) {
e.preventDefault();
$.ajax({ // create an AJAX call...
data: $(this).serialize(),
type: 'POST',
url: 'updatecontent',
success: function() {
mess("Success"); //mess is a function to generate a disappearing message box.
},
});
return false;
});
});
function updatecontentform(){
console.log('starting');
document.getElementById('contentdataform').submit();
}
views.py
#csrf_exempt
def updatecontent(request):
print("--------------------")
if request.method == "POST":
id = request.session['content_id']
fm = ContentForm(request.POST, instance= Content.objects.get(pk = id))
print("fm")
print(fm)
if fm.is_valid:
print("valid form")
form = fm.save(commit=False)
form.save()
else:
print("Not Valid")
return JsonResponse("Success", safe= False)
the output should be the message on the same page but it is reflecting on the new page with url '127.0.0.1:8000/updatecontent'

Display ValidationError In Ajax

I'm trying to display ValidationErrors using ajax. I've read many posts about this and tried many things but can't get it to work. I thiiinnnkkk ValidationErrors are passed as a dictionary and that they need to have json.dumps or .as_json() called on them before they are passed to ajax.
Here is some of my code:
forms.py
raise forms.ValidationError('Please enter a number greater than 100')
views.py
if form.is_valid():
[...]
else:
# i've tried this
error_dict= {'status':'form-invalid','form-errors':form.errors}
return HttpResponse(json.dumps(error_dict),content_type="application/json", status_code=400)
# and this
data = {'error':form.errors.as_json(), 'is_valid': False}
return JsonResponse(data, status_code=400)
# and more
ajax
error: function (data, xhr, errmsg, err) {
$('.error').html(data.form-errors)
},
--edit--
console.log:
{error: {…}, is_valid: false}
error:
__all__: Array(1)
0: "You cannot lock a lesson when the following lesson is unlocked"
length: 1
__proto__: Object
The error details are actually store in data['error'] not data.form-errors. You data will also have another item is_valid. The response data structure can be inspected by console logging data in ajax error. According to the structure access values and assign to elements.
In ajax error:
error: function (data, xhr, errmsg, err) {
console.log(data)
console.log(data.responseJSON)
// according to the structure of data access error value and assign
$('.error').html(data['error'])
},
in views.py form.errors should be passed. in JsonResponse() we need to pass a dictionary.
The first parameter, data, should be a dict instance. doc
if form.is_valid():
[...]
else:
data = {'error':form.errors, 'is_valid': False}
return JsonResponse(data, status_code=400)
In your script if you console.log('data.responseJSON') you could see something like this
In the above image I can access the error message for the field 'fname' as data.responseJSON.error.fname[0]

How to properly return Json reponse to template for ajax/jquery?

Here I am trying to search with the help of ajax and jquery with my django view. When I try to search like this by returning the JsonReponse instead of html_template it doesn't return data below the corresponding id in html
But When I return html from django view and create the new html for this searching results and including this template in the original template works perfectly but I find this a longer process So I tried to return json reponse from view and use that json objects in the template like this but it is not working.
How can I solve this ? I think I need to work on the ajax part .
def search_users(request):
q = request.GET.get('q')
if q:
users = get_user_model().objects.filter(is_active=True).filter(profile__full_name__icontains=q)
data = {'users': users}
else:
users = get_user_model().objects.filter(is_active=True)
data = {'users':users}
return JsonResponse(data)
ajax
$(function() {
$('#search_users').keyup(function() {
$.ajax({
type: "GET",
url: "{% url 'dashboard:search_users' %}",
data: {
'q' : $('#search_users').val(),
},
success: searchSuccess,
dataType: 'json'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search_users_results').json(data) #doing html instead of json works after returning html from django view
}
In the terminal
TypeError: Object of type QuerySet is not JSON serializable
[15/Mar/2020 14:02:53] "GET /admin/dashboard/search/users/?q=tyj HTTP/1.1" 500 22660
You have to extract values out of the query before sending it across instead of sending the model instance as it can't be serialized, is what the exception is saying.
So, you can just append .values() in the end and put in the list as below -
data = {'users': list(users.values())}
You may refer to it here.

django - passing data from server to js function via class based view

Django 1.6.3 +
Need to pass data to a class based view. where I want my jquery function to handle the data passed from the server. How would that be done ?
1.
Create a javascript/jquery function in your view which makes an $.ajax({options}); call to the url you want to send & receive data from (See #4 for an example).
2.
Have your views.py file import the json & HttpResponse module.
import json
from django.http import HttpResponse
3.
Add a function in your views.py to handle the request
def ExampleHandler(request):
Within this function, you can access parameters like request.POST['paramname'] or request.GET['paramname']. See https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.GET for more information.
To return data to the ajax call, store your data in a dictionary like this:
result = {
'success': True,
'foo': bar,
'more': data
}
and return the json like this:
return HttpResponse(json.dumps(result), content_type="application/json")
4.
Your original javascript function will look similar to this now:
function exampleRequest() {
$.ajax({
type: 'POST',
url: '/url-mapped-to-your-view',
data: {data: 'some-data-to-send-to-views'}, // May need to add a CSRF Token as post data (eg: csrfmiddlewaretoken: "{{ csrf_token }}")
error: function() {
alert('There was an issue getting the data...');
},
success: function(data) {
// Accessing data passed back from request, handle it how you wish.
alert(data.foo);
alert(data.more);
}
)};
}
5.
Ensure the url you make the ajax call to is correctly mapped in urls.py
You can probably pass data via args or kwargs
in views.py
class YourView(TemplateView):
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context['yourdata'] = self.kwargs['data']
return context
in urls.py
url(r'(?P<data>\w+)$', YourView.as_view()),