Django CRUD Ajax - javascript

I am building an application where I want users to be able to create posts. However, when I added the functionalities nothing happens after creating the 'Post' button, I can see that Django is not getting the url in the console.
Here is my Ajax code for Creating, Updating and Removing, the Update and remove work fine however the create is not working.
$(document).ready(function(){
var ShowForm = function(){
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType:'json',
beforeSend: function(){
$('#modal-post').modal('show');
},
success: function(data){
$('#modal-post .modal-content').html(data.html_form);
}
});
};
var SaveForm = function(){
var form = $(this);
$.ajax({
url: form.attr('data-url'),
data: form.serialize(),
type: form.attr('method'),
dataType: 'json',
success: function(data){
if(data.form_is_valid){
$('#post-list div').html(data.posts);
$('#modal-post').modal('hide');
} else {
$('#modal-post .modal-content').html(data.html_form)
}
}
})
return false;
}
// create
$(".show-form-create").click(ShowForm);
$("#modal-post").on("submit",".create-form",SaveForm);
//update
$('#post-list').on("click",".show-form-update",ShowForm);
$('#modal-post').on("submit",".update-form",SaveForm)
//delete
$('#post-list').on("click",".show-form-delete",ShowForm);
$('#modal-post').on("submit",".delete-form",SaveForm)
});
This is my views.py:
#login_required
def save_all(request,form,template_name):
data = dict()
if request.method == 'POST':
if form.is_valid():
form.save()
data['form_is_valid'] = True
posts = Post.objects.all()
data['posts'] = render_to_string('home/home_post.html',{'posts':posts})
else:
data['form_is_valid'] = False
context = {
'form':form
}
data['html_form'] = render_to_string(template_name,context,request=request)
return JsonResponse(data)
#login_required
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
else:
form = PostForm()
return save_all(request, form, 'home/post_create.html')
And this is the button I use:
<button class="btn btn-sm btn-primary show-form-create ml-auto" data-url="{% url 'home:post-create' %}">Post</button>
When I change the show-form-create to show-form-delete the PostForm pops up however when I change it back it seems not to be working. I have been on this issue for a while I cannot find what is causing the issue.
This is also available in my urls.py:
path('post/create/', views.post_create, name='post-create'),
I appreciate all the help in advance!

Related

Passing Values from JavaScript to Django

I have three forms like this:
<form id = "myForm" style="list-style-type: none;display: none;" class="form_class">
{% csrf_token %}
item1:
<input type="text" name="item1" style="width:10%;height:5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br><br>
<input id="close_form" type="reset" value="reset">
</form>
Below is the code I used to click the button so it will go the javascript method:
<form method="post">
{% csrf_token %}
<input class="bg-yellow text-white" value="RUN" name="runModel" type="submit"
onclick="sendValuesToBack()">
</form>
In the JavaScript method, I'm getting all three form's values. I want to send those to the Django Framework to perform several operations. How do I send this data from JavaScript to Django?
You can do this using JQuery Ajax in the template and by creating an "API view" in your views.py that is basically just a regular view that returns a JSONResponse after checking to verify the request is Ajax. As an example of the "API" option, using JQuery:
In your urls.py:
...
path('/api/post_form/', post_form_api, name="post_form_api"),
...
For the POST method in your views.py:
from django.http import JsonResponse
def post_form_api(request):
data = {}
if request.method == "POST":
form = MyDjangoForm(request.POST)
# do something with the form data
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
In your template:
<script type="text/javascript">
$("#myFormSubmitButton").click(function(){
var form_data = $("#formID").serialize();
$.ajax({ url: '{% url 'post_form_api' %}',
type: "POST",
dataType: "json",
data: form_data,
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
Alternatively, you can get the fields from all your forms individually, then send them in the Ajax data like so:
<script type="text/javascript">
$("#myFormSubmitButton").click(function(){
var csrfToken = $("input[name='csrfmiddlewaretoken']");
var item_1 = $("#item1").val();
var item_2 = $("#item2").val();
...
$.ajax({ url: '{% url 'post_form_api' %}',
type: "POST",
dataType: "json",
data: {'item1': item_1, 'item2': item_2, 'csrfmiddlewaretoken':csrfToken.val()},
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
If you have multiple forms you want to use this API for and are only submitting them one at a time, you can put a hidden field in your forms and do something like this in your views.py:
def post_form_api(request):
data = {}
if request.method == "POST":
form_name = request.POST.get('form_name', None) #the name of the hidden field identifying the form
if form_name is not None:
if form_name == "MyDjangoForm":
form = MyDjangoForm(request.POST)
# do something with the form data
...
elif form_name == "MyOtherForm":
form = MyOtherForm(request.POST)
# do something with the form data
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
If you are getting the data from all three forms in your template at once, you can do something like this in your views.py after sending all of the data using JQuery Ajax as above:
def post_form_api(request):
data = {}
if request.method == "POST":
item_1 = request.POST.get('item_1', None)
item_2 = request.POST.get('item_2', None)
item_3 = request.POST.get('item_3', None)
...
# do something with the collected form data here
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
When you are sending data via POST don't forget to pass along your CSRF token as in the example above (it should be in the serialized form data). This assumes you have a form on the page you can get it from, otherwise you can use something like this to get it:
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 = cookies[i].trim();
// 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');
If you don't want to deal with the CSRF token, you can mark the view with the #csrf_exempt decorator and remove the 'csrfmiddlewaretoken' data element from the Ajax call in the template, but it may not be ideal or the most secure. An example of that:
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
#csrf_exempt()
def post_form_api(request):
...
Now, without knowing more, this is basically just pseudocode (plus I just wrote this off the top of my head so it may have errors). This also depends on what type of views you are using, and whether you want to use the Django REST framework or not (the examples above are for regular, not class-based, views and do not require the Django REST framework to work).
If you post more details I can update my answer, but I think this should get you started.

Django template variables with ajax

How to update Django for loop template variable using response data on Ajax success. The status of the object is updating in the database I just can't get it to update the template. if I remove + response.applicant_pk the template is updated but always just the first item in the for loop
<div id="app_status_" class="_button__base_ _blue__button">
<strong>{{applicant.status}}</strong>
</div>
def applicant_status_change(request, applicant_id):
response_data = {}
if request.method =='POST' and request.is_ajax():
try:
applicant = Applicant.objects.get(pk=applicant_id)
position = applicant.applied_for.id
position = Position.objects.get(id=position)
count = position.get_all_applied_users_count()
applicant.status = request.POST['applicant_status']
applicant.pk = request.POST['pk']
response_data = {
"applicant_status": applicant.status,
"applicant_pk":applicant.pk
}
applicant.save()
return JsonResponse(response_data)
except Applicant.DoesNotExist:
return JsonResponse({'status':'Fail', 'msg': 'Object does not exist'})
else:
return JsonResponse({'status':'Fail', 'msg':'Not a valid request'})
$(".dropdown-item").click(function (e) {
var applicant_stat = $(this).text();
var pk = "{{ applicant.pk }}"
$.ajax({
url : '/dashboard/applicant/status/{{ applicant.pk }}/',
type : "POST",
data : {
'csrfmiddlewaretoken' : "{{ csrf_token }}",
'applicant_status': applicant_stat,
'pk': pk
},
success: function(response) {
$('#app_status_'+ response.applicant_pk).empty().append(response.applicant_status);
},
});
});
if it helps anyone else: I hadn't added the applicant pk to the div ID
<div id="app_status_{{applicant.pk}}" data-pid="{{ applicant.pk }}" class="_button__base_ _blue__button">{{applicant.status}}
</div>

Passing variable from javascript to django views

I am creating simple "rock paper scissors" game with some css animations and so on, where most of the stuff happens in javascript, as learning JS is what I am focusing on mostly at the moment.
User vs computer match also happens in javascript. When match is finished I am assigning users earned exp(points) to new variable.
What I am trying to do now is sending that data (earned exp) to the views, so I can save it back in a database (users.exp).
I think jQuery ajax or fetch api should do that if I am right but after hours of trying I probably just don't get it.
Any1 can give me some tips, explanation? Not just solution please.
Views:
#login_required
def profile(request):
if request.user.is_authenticated:
user = request.user
userObj = Profile.objects.filter(user=user)
usersLevel = userObj[0].level
usersPoints = userObj[0].points
context = {
'usersLevel': usersLevel,
'usersPoints': usersPoints,
}
return render(request, 'rps_app/game.html', context)
else:
print('No user logged in!')
return render(request, 'rps_app/game.html')
This is my template where Iam loading users data:
<script type="text/javascript">
var usersLevel = '{{usersLevel|safe}}';
var usersPoints = '{{usersPoints|safe}}';
</script>
js:
let users_level = Number(usersLevel);
let users_points = Number(usersPoints);
progressbar.style.width = `${users_points}%`;
...
javascript:
$(document).ready(function(){
$('#btn-ajax').click(function(){
$.ajax({
url: 'http://127.0.0.1:8000/game',
csrfmiddlewaretoken: "{{ csrf_token }}",
type: 'get',
success: function(data) {
console.log(data);
alert(data);
},
failure: function(data) {
alert('Your code is crap mate');
}
});
});
})
************ . E D I T E D . ***********
Thats what I got now:
js:
$(document).ready(function(){
$('#btn-ajax').click(function(){
$.ajax({
url: 'http://127.0.0.1:8000/test/earned_exp=100/',
csrfmiddlewaretoken: "{{ csrf_token }}",
success: function(data) {
alert('succes');
},
failure: function(data) {
alert('Your code is crap mate');
}}); });})
views:
def pass_variable(request, earned_exp=None):
some_variable = request.GET.get('earned_exp')
console.log(some_variable)
return HttpResponse('<h1>ok.{}</h1>'.format(earned_exp))
url:
path('test/<earned_exp>/', user_views.pass_variable, name='pass_variable'),
You can pass variables as URL parameters and get them through the request object.
$.ajax({
url: 'mycoolwebsite.com/path/?earned_xp=100'
success: function(e){
alert("success");
},
error: function(e){
alert("error")
}
});
class MyView(View):
def get(self, request):
xp = request.GET.get("earned_xp")
# do whatever you want with the XP now.
In case you want to send multiple URL parameters, you can seperate them by & here's an example url
https://example.com/?hello=world&goodbye=coding

How to upload a canvas image from javascript to Django

I am trying to send this toDataURL image to the server through AJAX. Unfortunately, every time it sends - no matter how I finagle it - I can only get either a 403 Forbidden error, a javascript error, or - at best - an empty dictionary item, while the other fields are accurate. Any ideas?
javascript
function SaveImage(n){
var imageFile = document.getElementById("img-file"+n);
// Set that you want to download the image when link is clicked
imageFile.setAttribute('download', 'image.png');
// Reference the image in canvas for download
imageFile.setAttribute('href', canvas.toDataURL());
addMeme(imageFile);
}
function addMeme(n){
var f= n;
var patch = '{% url "testing" %}';
var post_data = {
'csrfmiddlewaretoken':"{{ csrf_token }}",
imageBase64:f,
g: 'jjj',
};
$.ajax({
type: "POST",
url: patch,
data:post_data,
dataType: 'json',
success: function(data){
}
});}
views.py
def testing(request):
if request.method == 'POST':
response_json = request.POST
response_json = json.dumps(response_json)
data = json.loads(response_json)
print(data['imageBase64'])
return JsonResponse(data, safe=False)

AJAX: form.serialize() and csrf token together?

Can someone say whats wrong with this lane data:... inside saveForm function?
I have list of tasks in my page. Every task has there own form where users can send comments. It means that I have several forms in one page. When I add new task AJAX update list of comments and then I try to send comment by one of the form and it raise error : “CSRF token missing or incorrect”. I have {% csrf_token %} in all my forms.
It seems like I need send CSRF in AJAX. Where I did mistake?
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) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// TASK
$(function () {
var loadForm = function () {
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal").modal("show");
},
success: function (data) {
$("#modal .modal-content").html(data.html_group_task_form);
}
});
};
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize().append('csrfmiddlewaretoken', getCookie(csrftoken)),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#task-list").html(data.html_task);
$("#modal").modal("hide");
}
else {
$("#modal .modal-content").html(data.html_task_form);
}
}
});
return false;
};
// Create task
$("#task-add-button").click(loadForm);
$("#modal").on("submit", ".js-task-add-form", saveForm);
// Update task
$("#task-list").on("click", "#js-edit-task-button", loadForm);
$("#modal").on("submit", ".js-task-edit-form", saveForm);
});
//TASK COMMENT ADD
$(".task-comment-form").submit(function(event) {
event.preventDefault();
console.log(event.preventDefault());
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize().append('csrfmiddlewaretoken', getCookie(csrftoken)),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
var current_group = form.closest('.custom-list-group');
if (data.form_is_valid) {
current_group.find(".task-comments").html(data.html_task_comment);
}
else {
current_group.find(".task-comment-form").html(data.html_task_comment_form);
}
},
});
form[0].reset();
return false;
});
CODE ABOUT COMMENT ADD:
views.py:
def task_comment_add(request, project_code, task_code):
data = dict()
project = get_object_or_404(Project, pk=project_code)
task = get_object_or_404(Task, pk=task_code)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.save()
task.comments.add(comment)
data['form_is_valid'] = True
data['html_task_comment'] = render_to_string('project/task_comment_list.html' {'task': group_task})
else:
data['form_is_valid'] = False
else:
form = CommentForm()
context = {'project': project, 'task': task, 'form': form}
data['html_task_comment_form'] = render_to_string('project/task_comment_form.html', context, request=request)
return JsonResponse(data)
JS:
// TASK COMMENT ADD
$(".task-comment-form").submit(function(event) {
event.preventDefault();
console.log(event.preventDefault());
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
var current_group = form.closest('.custom-list-group');
if (data.form_is_valid) {
current_group.find(".task-comments").html(data.html_task_comment);
}
else {
current_group.find(".task-comment-form").html(data.html_task_comment_form);
}
}
});
form[0].reset();
return false;
});
.append is for DOM elements.
The result of .serialize is a string.
Why don't you just put the token in a hidden input in the form with a 'name' attr of 'csrfmiddlewaretoken'?
That will serialize it with the rest of your form data.
Here's what I did that worked for ajax forms with Django:
$('#ajax_form').submit(function(e){
e.preventDefault();
var form = this;
var action = $(form).attr('action'); // grab the action as url
var form_array = $(form).serializeArray(); // use serializeArray
form_array.push({ // *expand the array to include a csrf token*
name: 'csrfmiddlewaretoken',
value: getCookie('csrftoken') // getCookie function from django docs
});
var form_data = $.param(form_array); // set it up for submission
$.post(action,form_data,function(resp){
// do stuff after receiving resp
});
});
Basically, I used jquery's .serializeArray() instead of serialize.
.serializeArray() gives you an array of objects like this:
[{name:'name1',value:'value1'},{name:'name2',value:'value2'}]
calling $.param(serilaized_array_data) turns it into a string for submitting. So the key is to add the csrf token to the array. I did that in the code above on the line from_array.push({... with the *'s in the comments.
The problem was in my view. I use this and error disappeared:
context = {...}
context.update(csrf(request))

Categories