Post method in django using ajax - django

I have a form that I am trying to implement with Ajax, after inputing some content on the textbox, when I click on the sumbit button using my mouse, everything works fine (page didnt refresh, data posted on database, and new data displayed on the page). But when I try to submit data by pressing enter, the page is displaying only the serialized data from my form (nothing more, html file do not work)and it says in the console:
Resource interpreted as Document but transferred with MIME type application/json: "http://localhost:8000/try/".
current page looks exactly like this after pressing enter button(nothing more):
{"task": {"id": 52, "todo": "wws", "author": 1, "completed": false}}
these are the data that came from my form.
this is my views.py
class TodoList(View):
def get(self, request):
todo_list = ToDo.objects.filter(author_id=request.user.id)
form = AddTodo()
context = {
'todo_list': todo_list,
'form': form,
}
return render(request, 'trylangto/try.html', context)
def post(self, request):
form = AddTodo(request.POST)
if form.is_valid():
form.instance.author_id = request.user.id
new_form = form.save()
return JsonResponse({'task': model_to_dict(new_form)}, status=200)
else:
return redirect('trylang:todo-list')
return redirect('trylang:todo-list')
this is my main.js:
$(document).ready(function(){
$("#createbutton").click(function(){
var formdata = $("#addtodoform").serialize();
$.ajax({
url: $("#addtodoform").data('url'),
data: formdata,
type: 'post',
success: function(response){
$("#tasklist").append('<div class="card mb-1" ><div class="card-body">'+ response.task.todo +'<button type="button" class="close"><span aria-hidden="true">×</span></button></div></div>')
}
});
});
});
and here is my template:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% if user.is_authenticated %}
<div class="media content-section">
<form class="media-body pt-3" method="POST" id="addtodoform" data-url="{% url 'trylang:todo-list' %}">
{% csrf_token %}
<legend><h5>add new tasks</h5></legend>
<fieldset class="form-group ">
{{ form|crispy}}
</fieldset>
<button class="btn btn-outline-info float-right" type="button" id="createbutton">add</button>
</form>
</div>
{% endif %}
<div id="tasklist">
{% for task in todo_list %}
<div class="card mb-1" >
<div class="card-body">
{{task.todo}}
<button type="button" class="close">
<span aria-hidden="true">×</span>
</button>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
UPDATE: I am including my models.py just in case
class ToDo(models.Model):
todo = models.CharField(max_length=500)
date_posted = models.DateTimeField(default=timezone.now, editable=False)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='users')
completed = models.BooleanField(default=False)
this is what I get on the console when I use console.log(formdata):
csrfmiddlewaretoken=N91OUGSd6kBFkB1E2DMZuMW6qJD7cc3frPprwGMLTuupcg6PKYtt44jA4z5Lx6xX&todo=this%20is%20the%20content%20of%20my%20textbox

You don't need model_to_dict. So, try:
if form.is_valid():
form.instance.author_id = request.user.id
new_form = form.save()
return JsonResponse({'task': new_form}, status=200)
else:
return redirect('trylang:todo-list')
return redirect('trylang:todo-list')
EDIT
You are submitting the form not through ajax. When you click button it was submitting the form. So, e.preventDefault() should do the job.
$(document).ready(function(){
$("#createbutton").click(function(e){
e.preventDefault(); <--- You were missing this
var formdata = $("#addtodoform").serialize();
$.ajax({
url: $("#addtodoform").data('url'),
data: formdata,
type: 'post',
success: function(response){
$("#tasklist").append('<div class="card mb-1" ><div class="card-body">'+ response.task.todo +'<button type="button" class="close"><span aria-hidden="true">×</span></button></div></div>')
}
});
});
});

Related

I wanted to craete a 5 star rating system in django but it keeps getting this error:

i check with django document and But my problem was not solved
[08/Feb/2023 15:57:18] "POST /courses/2/learning-django HTTP/1.1" 403 2506
error:
Forbidden (CSRF token missing.): /courses/2/learning-django
this is my models
class Review(models.Model):
course = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews')
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
rating = models.IntegerField(null=True, validators=[MinValueValidator(1), MaxValueValidator(5)])
comment = models.TextField()
created = models.DateField(auto_now_add=True)
active = models.BooleanField(default=False)
def __str__(self):
return f'{self.first_name} {self.last_name}
my views:
def productDetailView(request, id, slug):
product = get_object_or_404(Product, id=id, slug=slug, available=True)
new_comment = None
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.course = product
new_comment.rating = request.POST['rating']
new_comment.save()
else:
form = ReviewForm()
return render(request, 'shop/product_detail.html', {'product': product, 'form': form})
js function:
$(document).ready(function(){
$('.rate .rate-item').on('click', function(){
var value = $(this).data('value');
$.ajax({
url: '{{ product.get_absolute_url }}',
type: 'POST',
data: {'rating': value},
success: function(response){
alert('Rating saved successfully!');
}
});
});
});
my template
<form method="post">
<div class="row">
<div class="col-md-6">
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Fast name" }}
</div>
</div>
<div class="col-md-6">
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Last Name"}}
</div>
</div>
<div class="col-lg-12">
<div class="form-singel">
<div class="rate-wrapper">
<div class="rate-label">Your Rating:</div>
<div class="rate">
<div data-value="1" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="2" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="3" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="4" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="5" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
</div>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Comment" }}
</div>
</div>
{% csrf_token %}
<div class="col-lg-12">
<div class="form-singel">
<button type="submit" class="main-btn">Post Comment</button>
</div>
</div>
</div> <!-- row -->
</form>
I used csrf_token in my form but it seems that dosen't work
and i searched in stackoverflow no one have same error
how do i fix it
If you want to make AJAX request, you need to add CSRF token to the data body.
$.ajax({
url: '{{ product.get_absolute_url }}',
type: 'POST',
data: {'rating': value, csrfmiddlewaretoken: '{{ csrf_token }}'},
success: function(response){
alert('Rating saved successfully!');
}
});
Original answer: https://stackoverflow.com/a/6170377/5711733
Basically what you miss is csrftoken in the form data.
You have two possibilities:
Either define view with #csrf_exempt:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def productDetailView(request, id, slug):
product = get_object_or_404(Product, id=id, slug=slug, available=True)
new_comment = None
Or load variable from cookie and pass it into headers (I'm using js-cookie library but you can find single functions on stack overflow that will fit your needs) - example:
$.ajax({
url: url,
type: 'POST',
headers: {
'X-CSRFTOKEN': Cookies.get('csrftoken'),
},
success: (data) => {
location.reload();
}
})
From what I know first solution should be more secure.

Not entering Else Statement from user.is_authenticated

In the castmascotvote view, everything is working when I'm authenticated, but not working otherwise. I have a print('entering not authenticated') right when it enters the else statement if the user isn't authenticated, but it never enters it, i'm boggled. I don't understand at all why it's not working. does anyone have any idea where I should start looking?
error message
The view didn't return an HttpResponse object. It returned None instead.
But I clearly have a HttpResponse object!
.html
<form class="mascotvoteform" action="{% url 'castmascotvote' mascot.id %}" id="{{mascot.id}}">
<div class="p-0"><h4>{{ mascot.name }} </h4> <p> by {{ mascot.author }} </p></div>
<div class="p-0"><img class="img-thumbnail" src="{{ mascot.image.url }}" style="width:250px;"></div>
<div class="row p-3">
{% if mascot.total_votes is 0 %}
<div class="col"><h5 id="mascotvotes{{mascot.id}}">0</h5></div>
<button class="col btn btn-primary" type="submit" id="castmascotvote{{mascot.id}}">Vote</button>
{% else %}
<div class="p-0 col"><h5 id="mascotvotes{{mascot.id}}">{{ mascot.total_votes }}</h5></div>
<button class="col btn btn-primary" type="submit" id="castmascotvote{{mascot.id}}">Vote</button>
{% endif %}
</div>
</form>
.script
$( document ).ready(function() {
$(".mascotvoteform").submit(function(e) {
{% if user.is_authenticated %}
e.preventDefault()
{% endif %}
let mascot_id = $(this).attr("id");
let url = $(this).attr('action');
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'mascot_id': mascot_id,
},
success: function(response) {
console.log('success', response)
$(`#mascotvotes${mascot_id}`).text(`${response['total_votes']}`)
};
},
error: function(response) {
console.log('error', response)
}
});
})
.views
def castmascotvote(request, mascot_id):
mascot = PoopMascot.objects.get(id=mascot_id)
user = request.user
if request.method == 'POST':
if user.is_authenticated:
if user in mascot.votes.all():
mascot.votes.remove(user)
else:
mascot.votes.add(user)
total_votes = mascot.total_votes()
data = { "total_votes":total_votes }
return JsonResponse(data, safe=False)
else:
print('entering user not authenticated')
messages.error(request, 'Please sign in to vote Poop Hero!')
return render(HttpResponseRedirect(reverse('user_login')))
else:
pass

Why Is Ajax Creating a New Comment When I'm Trying To Edit An Existing One?

I am trying to do a Django Blog in Class Based Views. They're proving very difficult to me anyway. I feel like I'm pretty close...I suspect it's creating a new one because I'm combining DetailView and trying to include an UpdateView in my page. I'm overriding POST on the DetailView...and perhaps that's why when I try to do my Update of the comment the overriden Post on DetailView is overriding that action?
Here's my code....
HTML...
<!DOCTYPE html>
<form method='POST' class="comment-form">
{% csrf_token %}
<div class="spacer284">
{{ form.comment }}
</div>
<button class="button7" type="submit">Submit</button>
</form>
<div class="spacer285">
{% include 'suggestion_comments.html' %}
</div>
</div>
{% endblock %}
Note that I'm doing an include so that I can loop through the comments more easily...
Here's the include template...
{% if suggestion_comments %}
<h2>Comments</h2>
{% for comment in object.suggestion_comments.all %}
<div class="spacer291">
<p>{{ comment.author }} {{ comment.created_on }}</p>
<p class="spacer290">{{ comment.comment }}</p>
<div class="spacer289">
<div class="upvote-comment-count">{{ comment.total_comment_upvotes }}</div>
<div class="hide-delete">
<button type="button" class="button6" data-href="{% url 'Suggestions:suggestion_comment_like' comment.id %}">Like</button>
</div>
<div class="hide-delete">
<button type="button" class="button2" data-href="">Reply</button>
</div>
{% if comment.author == request.user %}
<button type="button" class="button4" id="{{ comment.id }}" pk="{{ object.pk }}" href="{% url 'Suggestions:suggestion_comment_edit' object.pk comment.id %}">Edit</button>
<div class="spacer159" id="hide_payment" style="display:none;">
<input name="comment" id="commentInput" value="{{ comment.comment }}" class="name"/>
<button class="button7">Submit</button>
</div>
<div class="hide-delete">
{% if user.userprofile.eDirector_queue_delete_confirm == "Yes" %}
<button type="button" class="button5" data-href="{% url 'Suggestions:suggestion_delete' comment.id %}">Delete</button>
{% else %}
<button type="button" class="button3" data-href="{% url 'Suggestions:suggestion_delete' comment.id %}">Delete</button>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<h2>No Comments Yet</h2>
{% endif %}
I'm attempting to use AJAX to do a replace...
$(document).on('submit', '.comment-form', function(e) {
e.preventDefault();
var $this = $(this);
$.ajax({
type: "POST",
url: $this.data("href"),
data: $this.serialize(),
dataType: "json",
csrfmiddlewaretoken: "{{ csrf_token }}",
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(response){
console.log("so far");
$('.spacer285').html(response['form']);
$(".comment-form")[0].reset();
$('.spacer288').empty('spacer288');
},
error: function (request, status, error) {
console.log(request.responseText);
showAjaxFormErrors(JSON.parse(request.responseText));
},
});
});
$(document).on('click', '.button7', function(e) {
e.preventDefault();
console.log("working123");
var $this = $(this);
var comment = $('#commentInput').val();
console.log(comment);
$.ajax({
type: "POST",
url: $this.data("href"),
data: { comment: comment},
csrfmiddlewaretoken: "{{ csrf_token }}",
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
},
success: function(data){
console.log(data);
$('.comment-form1').html(data);
},
});
});
My DetailView...
class SuggestionDetailView(LoginRequiredMixin,DetailView):
model = Suggestion
context_object_name = 'suggestion_detail'
template_name = 'suggestion_detail.html'
def get_context_data(self, **kwargs):
context = super(SuggestionDetailView, self).get_context_data(**kwargs)
attachments = SuggestionFiles.objects.filter(suggestion=self.object.pk).all()
form = SuggestionCommentForm()
suggestion_comments = SuggestionComment.objects.filter(suggestion_id=self.object.pk).order_by('-created_on').all()
context['attachments'] = attachments
context['form'] = form
context['suggestion_comments'] = suggestion_comments
return context
def post(self, request, *args, **kwargs):
form = SuggestionCommentForm(request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.author = request.user
new_comment.suggestion = self.get_object()
new_comment.save()
self.object = self.get_object()
context = self.get_context_data(object=self.object)
html = render_to_string('suggestion_comments.html', context, request=self.request)
return JsonResponse({'form': html})
else:
form_errors = form.errors.as_json()
response = HttpResponse(form_errors, status=400)
response['content_type'] = 'application/json'
return response
MyCommentUpdateView...
class SuggestionCommentUpdateView(LoginRequiredMixin, UpdateView):
model = SuggestionComment
fields = ["comment"]
def form_valid(self, form):
form.instance.suggestion_id = self.kwargs["pk"]
return super().form_valid(form)
And my URLs...
path("a7900f81-b66a-41ea-afc2-d7735e6d4824/suggestion_detail/<uuid:pk>/suggestion_comment_edit/<int:id>",views.SuggestionCommentUpdateView.as_view(), name='suggestion_comment_edit'),
path("a7900f81-b66a-41ea-afc2-d7735e6d4824/suggestion_detail/<uuid:pk>/",views.SuggestionDetailView.as_view(), name='suggestion_detail'),
This is all almost working....My issue is when I click on the edit button and attempt to edit the comment....it works...and updates the database...but it's adding a new updated comment instead of just editing the existing comment. Thanks in advance for any thoughts on what I might be doing wrong.

asynchronus form submission django

I'm using ajax to submit a form, and it's working. But it's not working asynchronously. When I'm trying to upload files it uploaded successfully and then the page loads again. I want it to make asynchronously. In addition, I want to make a progress bar too. But things not working as I expected.
my forms.py
from django import forms
from .models import Comment
from .models import post
class UploadForm(forms.ModelForm):
class Meta:
model = post
fields = ('image', 'video', 'content',)
my views.py
def django_image_and_file_upload_ajax(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.instance.author = request.user
form.save()
return JsonResponse({'error': False, 'message': 'Uploaded Successfully'})
else:
return JsonResponse({'error': True, 'errors': form.errors})
else:
form = UploadForm()
return render(request, 'blog/upload.html', {'form': form})
and my upload.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<main>
<div class="container">
<div class="row">
<div class="col-md-8 my-5">
<div class="content-section" style="padding:10px 20px">
<form
enctype="multipart/form-data"
id="id_ajax_upload_form" method="POST"
novalidate="">
<fieldset class="form-group">
{% csrf_token %}
<legend class="border-bottom mb-4"><i class="fas fa-feather-alt text-muted mr-2"></i>Create a post</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<input type="submit" />
</div>
</form>
</div>
</div>
</div>
</div>
</main>
{% endblock content %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
// form upload
$('#id_ajax_upload_form').submit(function(e){
e.preventDefault();
$form = $(this)
var formData = new FormData(this);
$.ajax({
url: window.location.pathname,
type: 'POST',
data: formData,
success: function (response) {
$('.error').remove();
console.log(response)
if(response.error){
$.each(response.errors, function(name, error){
error = '<small class="text-muted error">' + error + '</small>'
$form.find('[name=' + name + ']').after(error);
})
}
else{
alert(response.message)
window.location = ""
}
},
cache: false,
contentType: false,
processData: false
});
});
// end
where i get wrong?
Ok, Got it! But anyone know about how to add a progressbar will be helpful.

Django, uploading images throwing 403 CSRF token missing error on Ajax call

I am trying to upload multiple files using Django. The idea is that while creating a blog post the user can also add images to the post. I am using Ajax to submit the blog post, however, it seems that after adding the image form the "submit" button doesn't work and my post does not get created. I have already built two models, Images and Post. Below are my codes related to this functionality. My project name is register and images are in an app called 'home':
(If I remove the image upload functionality the post is created successfully, so the ajax is working correctly)
my image model:
my post_creat view in home app views:
#login_required
def post_create(request):
data = dict()
if request.method == 'POST':
image_form = ImageForm(request.POST, request.FILES or None)
images = request.FILES.getlist('image')
form = PostForm(request.POST)
if form.is_valid() and image_form.is_valid():
post = form.save(False)
post.author = request.user
post.save()
for i in images:
image_instance = Images(image=i,post=post)
image_instance.save()
data['form_is_valid'] = True
posts = Post.objects.all()
posts = Post.objects.order_by('-last_edited')
data['posts'] = render_to_string('home/posts/home_post.html',{'posts':posts},request=request)
else:
data['form_is_valid'] = False
else:
image_form = ImageForm
form = PostForm
context = {
'form':form,
'image_form':image_form
}
data['html_form'] = render_to_string('home/posts/post_create.html',context,request=request)
return JsonResponse(data)
my javascript code for handling the ajax request:
$(document).ready(function(){
var ShowForm = function(e){
e.stopImmediatePropagation();
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);
}
});
return false;
};
// change form to FormData
// var form = $(this)
// processData, contentType were removed
var SaveForm = function(e){
e.stopImmediatePropagation();
var data = new FormData($('form').get(0));
$.ajax({
url: $(this).attr('data-url'),
type: $(this).attr('method'),
data: data,
processData: false,
contentType: false,
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
$('.create-post-btn').click(ShowForm);
$('#modal-post').on("submit",".post-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)
});
My post_create.html file:
<form method="POST" data-url="{% url 'home:post-create' %}" class="post-create-form" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" >Create a Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" style="overflow-y: auto;">
{{ form|crispy }}
<button type="button" id="show-image-upload-inputs" class="btn btn-sm mr-auto btn-primary pb-1">
<span><i class="fas fa-camera"></i></span>
</button>
<div id="image-upload-div" class="mt-1" style="display: none;">
<hr class="my-2">
<p class="mx-2 text-muted small">Add up to four images to your post</p>
<div class="d-flex flex-row justify-content-between px-1">
{{ image_form }}
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Post</button>
</div>
</form>
**the display hidden is just a javascript functionality to show the form when use clicks on the vamera button.
my image model:
class Images(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='images')
image = models.FileField(upload_to=upload_to_uuid('media/post_images/'),verbose_name='Image')
date_added = models.DateTimeField(auto_now_add=True)
my project (register) settings.py:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
my project (register) urls.py;
urlpatterns = [
#Has to be included for Forgot Password funcitonality on main page
path('', include('django.contrib.auth.urls')),
path('admin/', admin.site.urls),
path('',views.user_login,name='user_login'),
path('',include('main.urls'),name='main'),
url(r'^home/',include(('home.urls','home'), namespace='home'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT ) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
and my media folder is created at register/media
EDIT: I have changes my Ajax function and now I'm using FormData, however, I am getting a
Forbidden (CSRF token missing or incorrect.): /home/post/create/
[06/Apr/2020 01:18:53] "POST /home/post/create/ HTTP/1.1" 403 2513
Error,when I clikc on submit, however, I do have a csrf_token.How can I resolve this issue?
Your Code Post Model Should be like this
class Post(models.Model):
title=models.CharField(max_length=50)
sub_title=models.CharField(default="This is the subtitle of the post ",max_length=150)
content=models.TextField(max_length=4000)
date_posted=models.DateTimeField(default=timezone.now)
blog_image_1=models.ImageField(Blank=True,Null=True,upload_to='media')
blog_image_2=models.ImageField(Blank=True,Null=True,upload_to='media')
blog_image_3=models.ImageField(default='default.jpg',upload_to='media')
author =models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.title
The media directory be like this
MEDIA_ROOT=os.path.join(BASE_DIR,'media')
MEDIA_URL='/media/'
And Html Be like
<body>
<div class="container">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="'border-bottom mb-4">Post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn-outline-info" type="submit"> Submit</button>
</div>
</form>
</div>
</body>
And Use Class Base Views They More PowerFull
class PostCreateView(LoginRequiredMixin,CreateView):
model = Post
fields = ['title','sub_title','content','blog_image_1','blog_image_2','blog_image_2']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)