Django: how to add csrf token when prepending a from using ajax - django

I am adding a comment functionality in my project. And I am using ajax to make it dynamic so that when the user clicks on the comment submit button it will be added in the comment section dynamically without refreshing the page. But the problem is when prepending a form using ajax I cant add csrf token like this
{% csrf_token %}
in the form because ajax wouldn't understand it and take it as text.
function getids(postid){
console.log(postid)
$(postformid).one('submit', function(event){
event.preventDefault();
console.log(event)
console.log("form submitted!") // sanity check
create_comment(posted);
});
}
// AJAX for posting
function create_comment(postid) {
console.log("create comment is working!") // sanity check
console.log(postid)
console.log(talkid)
$.ajax({
url : "create_comment/"+postid, // the endpoint
type : "POST", // http method
data : { the_comment : $(cmtext).val() }, // data sent with the post request
// handle a successful response
success : function(json) {
$(cmtext).val(''); // remove the value from the input
console.log(json); // log the returned json to the console
$(talkid).prepend(
"<div class='col-1 p-0'><form' id=upvote' method='POST'>{%"csrf_token"%}<button
class='btn btn-md btn-outline-danger btn-
block p-auto' id='btnid' onclick='---' type='submit'></button></form></div>");
console.log("success"); // sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
}
});
};
pretending my form here
<div class="row m-0" id="talk{{post.id}}"></div>
is there any other way around?

Use
{% csrf_token %}
just before the form tag inside your template.

Related

Django & Ajax : data get lost between the view and the template

Using Ajax and Django, my data get lost when sent back to my template and I can't retrieve them.
Here is my code and the logic :
Following the dependent dropdown lists tutorial offered by ["Simple is Better Than Complex"][1]
I have implemented an Ajax request.
Here is the html code:
<p class="multiple-choice" id="mandate-city" data-url="{% url 'officials:ajax_load_mandate_city' %}">Local Mandate: {{ form.mandate_city }}</p>
The ajax request is fired from this script:
<script>
$("#id_departments").change(function (){
var url = $("#mandate-city").attr("data-url");
var departmentId = $(this).val();
$.ajax({
url: url,
data: {
'department': departmentId
},
success: function (data){
$("#id_mandate_city").html(data);
console.log(data);
}
});
});
</script>
After check with console.log, the data are collected by the script. Then, they reach the view.
Here is my view:
def load_mandate_city(request):
department_id = request.GET.get('department')
mandate_city = MandateCity.objects.filter(department_id=department_id).order_by("department")
return render(request, "officials/mandate_city_list.html", {mandate_city: mandate_city})
With a print, I have checked, and the data are treated as planned.
Then the data are sent back through the url:
path('ajax/load_mandate_city/', views.load_mandate_city, name="ajax_load_mandate_city")
They seem not to reach the template:
{% for mandate in mandate_city %}
<option value="{{ mandate.pk}}">{{ mandate.get_mandate_display }}</option>
{% endfor %}
And I could not track them in my script. :-/
Can somebody let me know where the bug is ?
Thanks.
[1]: https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
did you try to return the information in a json object and then render it with client side js? in general when you use ajax (or fetch) you wanna use the information returned so it's better to return it as a data type,
if you do want to return the html response you should probably not use ajax but rather a form

Accessing Objects Attributes Within Ajax

I am adding ajax to my website. I originally had this button:
{% for item in notifications %}
<a class='delete' href="{% url 'delete' item.slug %}">
But changed it to Ajax.
{% for item in notifications %}
<a class='delete'>
$(document).on('click', '.delete', function (e) {
$.ajax({
url: '/users/ajax/delete/',
data: {
// here I was to call the 'delete' function in the 'django.notifications' package
// something like 'notifications.delete(slug)'
},
dataType: 'json',
success: function (data) {
alert("Working");
}
});
});
This Ajax fires correctly, but I don't know how to get item.slug in Ajax. I guess I could do this <a class='delete' slug="{{ item.slug }}"> and access the slug, but it seems really sloppy.
Is there a way to pass an object's attributes to Ajax without setting it as a value within the html code itself?
Thank you.
You can store the value of the notification in a variable while rendering the HTML as shown below in the HTML section. Once you have notifications value in your script code. You can check the index of the clicked anchor and retrieve the item associated with that index.
$(document).on('click', '.delete', function(e) {
let elem = $(this);
$.ajax({
url: '/users/ajax/delete/',
data: {
// here I was to call the 'delete' function in the 'django.notifications' package
// something like 'notifications.delete(slug)'
},
dataType: 'json',
success: function(data) {
alert("Working");
//new code below
let index = $("a.delete").index(elem);
let item = notifications[index];
//You can access slug and other attributes of item now.
}
});
});
<script>
const notifications = {% notifications %}
</script>

How to get response back from Django API to Calling HTML Page i am posting an image to Api?

How I can call a Django API from another Django Project (or from any other project) and get the response back after some processing on the same calling page (the page from which I called the API)
I am calling the API from form action ....but API shows the response in a new blank page
Here is API CODE: (//skipping some code to avoid confusion)
def IdealWeight(request):
#defining a list of data to send back to html
list_of_data=[]
list_of_data.append(name)
list_of_data.append(fatherName)
list_of_data.append(registration)
print(list_of_data)
# outPut_Data = ast.literal_eval(list_of_data)
# return render(request,'LibraryForm.html',{'data1':outPut_Data})
return JsonResponse(list_of_data,safe=False)
I want list_of_data on the calling page in some variable.
Here is my HTML Code from which i am calling the API:
<form action="http://127.0.0.1:8000/idealweight/?image/" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" class="form-control-file" name="image" onchange="readURL(this);" required>
<input type="submit" class=" btn btn-primary" title="Process" value="Process" id="processButton">
</div>
{{ data1 }}
</form>
From HTML page, I am sending a picture to API (API build in Django)
and from that, I want to send an array or list of data extracted from the image and want to show that on same HTML page....................from which I called the API how I can do that?
hope I am clear what I want?
Using an Ajax call would be better choice. you would be doing something along the line.
$(document).ready(function (e) {
$('#upload').on('click', function () {
var file_data = $('#file').prop('file');
var form_data = new FormData();
form_data.append('file', file_data);
$.ajax({
url: 'http://127.0.0.1:8000/idealweight/?image/',
contentType: false,
data: form_data,
type: 'post',
success: function (response) {
// use response to update html
},
error: function (response) {
// use response to update html
}
});
});
});
and your template would be something like
<input type="file" id="file" name="file"/>
<button id="upload" type="button">Process</button>
note: you might get cross origin request block error. so you have to allow that explicitly.

Execute Django function just when javascript is dissabled

I have an Html template with a form inside of it.
<form id="my_form" method="post" action="/register/">
<input id="cemail" name="email" size="25" class="textbox required email" style="width: 250px"> <br><br>
<input id="csubmit" type="submit" onclick="Clicked();" value="Send" />
I also have a Jquery code for test if the e-mail introduced is correct:
<script type="text/javascript" src="/js/jquery.validate.js"></script>
<script>
function Clicked() {
$("#my_form").validate().form();
value = $("#cemail").val();
alert("ufffff");
$.get("/exists/", {email: value}, function(data) {
$('#text')[0].innerHTML=data;
});
}
</script>
Until here everything is ok. My problem appears when I execute the program. Always the action="/register" is launched, and I don't want that it occurs. I would like that:
If jquery is desactivated on the client browser, execute the action that the form has. In case that jquery is activated on the client browser, just execute the "Clicked()" function and not the form's action ("/register/" --> calls django function)
Does anyone help me to do that? Is it possible?
You need to return false from your Clicked function.
Return false from an event handler in JavaScript tells the browser not to execute the default action associated with that element (a link, or a button).
If you want to be super-duper correct, you should actually attach yourself to your form's submit action and return false there. This will allow a user to hit the return key to submit your form, but stop the browser from doing a POST:
$('#my_form').submit(function(){
$("#my_form").validate().form();
value = $("#cemail").val();
alert("ufffff");
$.get("/exists/", {email: value}, function(data) {
$('#text')[0].innerHTML=data;
});
return false;
});
If JavaScript is disabled, the browser will execute the default action for the form normally.

Ajax form submission, files not getting submitted

I am trying to implement AJAX form submission for my Django forms.
The files are getting submitted without AJAX, so the logic at the serverside seems to be working. and with ajax, the rest of the values except the files get submitted.
Here is the code that I am implementing,
AJAX form Submission
(function() {
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false, // obviates need for sameOrigin test
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
})();
jquery
$('#save-form').live('submit', function(event) { // catch the form's submit event
event.preventDefault();
$.ajax({ // create an AJAX call...
data: $(this).serialize(), // get the form data
type: $(this).attr('method'), // GET or POST
url: '/save/', // the file to call
success: function(response) { // on success..
$('#modalsave-form').html(response); // update the DIV
}
});
return false;
});
HTML Form
<form class="form-horizontal" id="save-form" enctype="multipart/form-data" method="post" action="/save/">
<div class="control-group">
<label class="control-label" for="id_body">Write Something</label>
<div class="controls">
<textarea class="typeaheadfun" id="id_body" rows="3" cols="100" name="body" placeholder="Scribble Body" style="width: 455px;"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_media">Add a File</label>
<div class="controls">
<input type="file" name="media" id="id_media"/>
</div>
</div>
<hr>
<input class="btn btn-primary pull-right" type="submit" value="Post!" />
<br>
{% csrf_token %}
</form>
When you submit an HTML form it usually sends form's data to the server using either GET or POST data HTML headers. When however you need to send binary data or attached file(s) to the server efficiently, HTML as part of it's spec has a different method for sending such data. enctype attribute of <form> tag specifies using which method should the browser send the data to the server. To send files, multipart/form-data is widely used encoding method.
When you try to send form without ajax, browser sends file data to the server using multipart/form-data encoding however when you submit the form using ajax you do the following:
data: $(this).serialize()
That step does not encode data the same way as server expects the data hence your ajax does not work.
To make it work, instead of manually submitting form's data, you should submit the whole form using ajax. Doing it manually is tricky plus there are plugins which do that already. One such plugin is jQuery Form Plugin. It allows to submit the whole form using ajax. The following is js code which should give you an idea on how to integrate it with your setup:
$('#save-form').live('submit', function(event) {
event.preventDefault();
$(this).ajaxSubmit({
url: '/save/', // the file to call
success: function(response) {
$('#modalsave-form').html(response);
}
});
return false;
});
Another option is to use the FormData interface that absolves the need for a plugin
https://developer.mozilla.org/en-US/docs/Web/API/FormData
Sample Code: (Adapt to suit your needs)
`
$('#fupload').click(function(){
var xhr = new XMLHttpRequest();
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
$.ajaxSetup({
headers: { "X-CSRFToken": token }
});
var formData = new FormData($('form')[0]);
formData.append('file',xhr.file);
$.ajax({
url: '/myurl/', //server script to process data
type: 'POST',
xhr: function() { // custom xhr
myXhr = xhr;
//if(xhr.upload){ // check if upload property exists
// xhr.upload.addEventListener('progress',progressHandlingFunction, false);
// for handling the progress of the upload
//}
return xhr;
},
// Form data
data: formData,
//Ajax events
success: function(server_response){
$( '#path' ).val("Success");
},
error: function(jqXHR, textStatus, errorThrown ){
$( '#path' ).val(errorThrown);
},
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
});
`