Django view not getting ajax request - python

I have a script in my template that tries to send data to a django view during onbuttonclick event. My problem is that the request doesn't seem to make it to the view. The browser console sees the request properly and all, but the django view does't even return true when i call request.is_ajax().
request.method returns GET instead of POST, and the data is empty. This behavior is persistent regardless of the request type.
html
<a onclick="setGetParameter(this)" pid="some_id">Some Text</a>
.js
<script>
var csrftoken = Cookies.get('csrftoken');
function setGetParameter(el){
var stuff = $(el).attr('pid');
$.ajax({
type: 'POST',
headers: { "X-CSRFToken": csrftoken },
url: '/view_url/',
data: {'datatopass': stuff},
success: function(response){
alert(response);
}
});
}
</script>
urls.py
path('view_url/', views.test),
path('', views.home),
views.py
def test(request):
output = request.is_ajax()
return HttpResponse(output)

In Django 3.1 is_ajax() method is deprecated. See Miscellaneous Django 3.1
So for Django >= 3.1 you can do it like that:
if request.headers.get('x-requested-with') == 'XMLHttpRequest':
is_ajax = True
else:
is_ajax = False
And make sure that the following line added in AJAX request headers:
"X-Requested-With": "XMLHttpRequest"
I would be use jQuery click method:
<a pid="some_id">Some Text</a>
<script>
var csrftoken = Cookies.get('csrftoken');
function setGetParameter(el){
var stuff = $(el).attr('pid');
$.ajax({
type: 'POST',
headers: { "X-CSRFToken": csrftoken },
url: '/view_url/',
data: {'datatopass': stuff},
success: function(response){
alert(response);
}
});
}
$(document).ready(function(){
$('a[pid]').click(function(){
setGetParameter(this);
});
});
</script>
Also I would be use JsonResponse objects:
from django.http import JsonResponse
def test(request):
output = request.is_ajax()
return JsonResponse({'is_ajax': output})
In order to serialize objects other than dict you must set the safe parameter to False:
response = JsonResponse([1, 2, 3], safe=False)

After days of beating my head against a wall, I chose to go with a different implementation. It appears I can only render the data on the page that initially sent the request.

Related

Failed to load resource: the server responded with a status of 403 (Forbidden)?

i am posting javascript localstorage object to backend(django). I am passing it through ajax.
this is the code in frontend.
function checkout_(){
console.log("checkout");
for(v in list1){
object=Object.values(localStorage)[v];
object = JSON.parse(object)
}
//ajax here
console.log(object.length);
$.ajax({
url: '{% url "chout" %}',
data: {
'object': object
},
method: "POST",
dataType: 'json',
success: function (data) {
alert("success");
}
});
i have given this function to a button via onclick.
<button class="bg-danger text-white " onclick="checkout_()">Go To Checkout Counter</button>
when i click on this button this error "Failed to load resource: the server responded with a status of 403 (Forbidden)" happens.
in the views.py this is the code.
views.py
def checkoutnow(request):
return render(request, "mart/checkout.html")
I hope this detail is enough to explain the problem..Thankyou
You have to pass csrfmiddlewaretoken also in the post call because of csrf middleware set in the settings
const csrf = "{{ csrf_token }}";
and add this key, value pair to your data:
data: {'csrfmiddlewaretoken':csrf, 'object': object },
You can skip this and just use GET instead of POST if feasible.

Flask request returns None; but Ajax Post is successful

In flask I'm using a GET request to first render a template and get data the user has selected.
#app.route('/surveys', methods=['POST', 'GET'])
def register_form():
if request.method == 'GET':
return render_template('survey_table.html')
else:
example = request.json
return json.dumps(example)
This data (which is the #ids of checkboxes selected in a table) is then posted back to FLASK using an ajax Post request. Since the data was initially an array I have used JSON.stringify
$(document).ready(function() {
$('#submit').click(function() {
var list = [];
var checkBoxes = $('#surveyDetails').find("input[type='checkbox']:checked");
checkBoxes.each(function() {
var currentRow = this.parentNode.parentNode;
list.push(currentRow.getElementsByTagName("td")[0].innerText);
});
// now names contains all of the names of checked checkboxes
$.ajax({
contentType: "application/json",
url: '/surveys',
type: 'POST',
data: JSON.stringify({'Hello': list}),
success: function (result) {
alert(result);
},
error: function (result) {
alert("error!");
}
}); //end ajax
});
});
The Problem:
I can see that the ajax post is executed successfully since I am able to see the selected ids as an alert once I click the submit button. However, in flask when I return this JSON object, I always get a null response.
I have already tried get_json(force=True). Still the same result.

ajax json post request to flask

I am struggling to send a ajax post request but cannot figure out where i am going wrong, i have this form which i submit with js and along with that form i want to send the id of a div:
<script type="text/javascript">
$(document).ready(function() {
$('input[type=radio]').on('change', function() {
$(this).closest("form").submit();
var poll_id = $(this).closest("div").attr("id");
var data = {poll_id};
console.log(JSON.stringify(data));
$.ajax({
url: '/poll',
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
dataType: 'json'
}, function(data) {
console.log(data);
});
});
});
</script>
and in flask i try to request it with request.get_json() but keep getting error 400, the form and db.commit() works fine:
#app.route('/poll', methods=['GET', 'POST'])
def poll():
polltodb = pollingresult(request.form['points'])
session['points_session'] = request.form['points']
db.session.add(polltodb)
db.session.commit()
data = request.get_json()
print data
but the get_json() fails.
$(this).closest("form").submit(); tells your html page to submit the form. If any javascript after that line even executes you'd be making a separate XHR request (e.g. 2 requests, the data would never be in the same request using this approach). To accomplish what you're trying to do I'd take a different approach:
Add a hidden element to your form. e.g. <input type="hidden" name="poll_id" id="myHiddenField">
Update your javascript:
<script type="text/javascript">
(function(){
$('input[type=radio]').on('change', function () {
$('#myHiddenField').val($(this).closest("div").attr("id"));
$(this).closest("form").submit();
});
});
</script>
Then, access the data through the form as you normally would and don't worry about get_json()

Can't get AJAX POST working in Django

I can't do a POST ajax request in Django. If I do a GET request, it works fine. I think it may be a csrf token problem, but I can get it to work
My view:
#login_required
def add_share_points(request):
user = request.user
profile = request.user.profile
if request.method == 'POST':
value = 5.0
# Premia o usuário ao compartilhar conteúdo
VirtualCurrencyTransaction.objects.create(
user=request.user,
reason=2,
description='Você completou seu perfil',
value=value
)
return "ok"
My AJAX request:
$('.my-button').on('click', function(e) {
e.preventDefault();
var pointsCount = $(this).hasClass('homepage-facebook-share') ? 3 : 2;
$.ajax({
type:"POST",
url: "/add_share_points",
data: {
points: pointsCount,
}
}).done(function() {
alert('Posting completed.');
}).fail(function(){
alert('Error while posting.');
});
});
In my script, I also have this setting:
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/).test(method);
}
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);
}
}
});
What is wrong with my code? It gave my a 500 error code, but no further explanation in the logs.
I will point out several things to correct, some are just ways to do it in a django manner and not problems.
In your view
return HttpResponse(
json.dumps({'result': 'ok',}),
content_type="application/json"
)
In your ajax
url: "/add_share_points",
should be:
url : {% url '<name in url.py>' %},
and you need to add (to the data object):
csrfmiddlewaretoken: '{{ csrf_token }}'
Inside the ajax request, insert this after data:
// handle a successful response
success : function(json) {
if (json.result=== 'ok'){
console.log('It works!');
}else{
console.log('Something wrong with response');
}
// handle a non-successful response
error : function(xhr,errmsg,err) {
console.log(err);
}
In your script
instead of CSRF_TOKEN use '{{ csrf_token }}'
Please use my suggestions and give me feedback and I will update the answer. The two with csfrtoken are probably the problems your having. If you put Django in Debug mode it will be easyer to find out.
My Suggestion
Create a form with what you need to post to gain some features in the validation process.

Using the Django URL Tag in an AJAX Call

There are LOTS of post and pages discussing the use of Django and AJAX, and I've read hundreds over the past day or so looking for the answer to this question. A quick overview:
May of the examples show a hard-coded URL like this:
$.post("/projects/create/", {"name" : name}, function(data) {...
or some use the URL template tag, but with no parameters:
$.post("{% url create_project %}", {"name" : name}, function(data) {...
However, I'd like to include a Django-style parameter in a URL. Here's my url definition:
url(r'ajax/entity_name/(?P<pk>\w+)/$',EntityAjaxView.as_view(),name='entity_name'),
Yes, I'm using a class based view, and it is based on DetailView. This view looks by default for a pk value to be provided in the URL, and in a normal template I would use:
{% url entity_name id_number %}
to provide a link. In my code, I want to grab the value entered in an input box for the pk value. Here is a snippet of my JavaScript (which doesn't work):
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val()
$.ajax({
type: "GET",
url: '{% url entity_name id_number %}',
So, my question is, can I use the URL template tag with a value from an input box?
(I know that I could use POST instead of GET and pass the id_number in the POST data, but that won't work well with the DetailView.)
Django is a server-side application. Javascript is client-side. Django templates get rendered on the server, so {% url entity_name id_number %} is evaluated on the server side, and then it's value is returned to the client. Just because of this, it's impossible for you to combine Django templates with javascript. However there are couple of things you can do to solve your problem.
Since you are making an ajax call, and the ajax call depends on some user input, usually the best route for the client to send any type of user input to the server is by either using querystring (thing after ? in the URL) or by sending a POST data. So the simplest thing is to change your your url not to include the pk in the url, but for the view to get that as part of GET or POST data.
url(r'ajax/entity_name/$', EntityAjaxView.as_view(), name='entity_name'),
and the view (sorry I'm not familiar with class based views):
def entity_name(request):
pk = request.GET.get('pk')
...
That seems to me to be the most elegant solution. If however you absolutely need to construct the url on the client side, you can generate a template url on the server side and then replace whatever parts you need on the client side to get the full url. This however requires more maintenance and therefore is more error prone. Simple js example of this approach:
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val(),
url = '{% url entity_name 0 %}'.replace('0', id_number);
$.ajax({
type: "GET",
url: url,
...
});
It is possible to set an Ajax url on the element you are selecting using an attribute and it will behave like Django urls. Importantly, you can even access the url in Javascript file. I use it a lot
HTML
<div class="card-body" id="js-products" data-url="{% url 'chart-data' %}">
<div class="chart-area">
<canvas id="testChart"></canvas>
</div>
</div>
Note: the data-url attribute set on parent div
JAVASCRIPT
$(document).ready(function () {
var endpoint = $("#js-products").attr("data-url");
var defaultData = [];
var labels = []
$.ajax({
method: 'GET',
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.data_default
setChart()
},
error: function (error_data) {
console.log(error_data)
}
})
function setChart() {
var ctx = document.getElementById('testChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
labels: labels,
datasets: [{
label: 'Monthly Performance',
data: defaultData,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
});
DJANGO VIEWS
Am using django rest framework class view but you can use either of function or class based view
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
labels = ['Products', 'User', 'May']
data_default = [SeedProduct.objects.all().count(),
User.objects.all().count(), 4]
data = {
'labels': labels,
'data_default': data_default,
}
return Response(data)
DJANGO URLS:
import the view class from views
path('api/chart/data', views.ChartData.as_view(), name="chart-data"),
It's pretty time consuming to go round trip to a server just to fetch a URL. The best strategy to keep URLs dry and avoid this is to generate javascript that emulates Django's native url reverse function and then serve that code statically with the rest of your client side JS.
django-render-static does just that.
This worked for me.
my URL was:
path('myurl/<str:type>', views.myfunction, name='myfunction')
my views.py file:
def myfunction(request,type):
return render(request, "payment.html", context)
In my template, I solved the issue by:
<button type="button" class="btn"
onclick="myfunction('forward');">My Button Name
</button>
<script>
function myfunction(type){
let url = "{% url 'appName:myfunction' 'ok' %}".replace('ok', type);
$.ajax({
method: 'POST',
url: url,
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
}
});
}
</script>

Categories