I'm trying to write a simple form using Ajax. After multiple attempts, I keep getting "POST /app/emails/ HTTP/1.1" 200 13950 in Terminal, but the model doesn't update (even when I look in the shell).
I really would like the abilityt to submit the form within the modal, and update the image behind it. However if that's not possible I can settle for an alternative.
Really stuck here, would love any advice!
emails.html
<div class="modal fade" id="addEmailModal" data-bs-backdrop="static" data-bs-keyboard="false"
tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Add New Email</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" id='add-email'>
{% csrf_token %}
<fieldset class="form-group">
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close
</button>
<button class="btn btn-primary" type="submit">Add</button>
</div>
</form>
</div>
</div>
</div>
Javascript
$("#add-email").submit(function (e) {
e.preventDefault();
alert('working');
$.ajax({
type: 'POST',
url: "{% url 'add-emailname' %}",
data: {
email_name = $(this).email_name,
cadence = $(this).cadence
},
success: function (response) {
alert("Email name successfully added!")
$("#add-email").trigger('reset'); //clear the form
},
error: function (response) {
// alert the error if any error occured
alert(response["responseJSON"]["error"]);
}
})
}
views.py
def emails(request):
context = {
'emails': UserEmail.objects.all(),
'form': EmailCreateForm()
}
return render(request, 'app/emails.html', context)
def addEmailName(request):
if request.is_ajax and request.method == "POST":
form = EmailCreateForm(request.POST)
if form.is_valid():
form.save()
returned_email_name = form.cleaned_data.get('email_name')
messages.success(request, f'{returned_email_name} added as new Email!')
# send to client side.
return JsonResponse({"success": True}, status=200)
else:
# some form errors occured.
return JsonResponse({"error": form.errors}, status=400)
# some error occured
return JsonResponse({"error": ""}, status=400)
forms.py
class EmailCreateForm(ModelForm):
class Meta:
model = UserEmail
fields = ['email_name', 'cadence']
def __init__(self, *args, **kwargs):
super(EmailCreateForm, self).__init__(*args, **kwargs) # Call to ModelForm constructor
self.fields['email_name'].widget.attrs['rows'] = 1
self.fields['cadence'].widget.attrs['rows'] = 1
urls.py
urlpatterns = [
path('', views.home, name='app-home'),
path('emails/', views.emails, name='app-emails'),
path('post/ajax/addEmailName', addEmailName, name='add-emailname')]
Related
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.
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>')
}
});
});
});
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)
I tried updating a user's profile picture using a function view (ajax) but I keep getting the error below:
raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'emp_photo'
The same technique I am using is being used on CharField and TextField without issues.
Please see below for my codes.
views.py
#login_required(login_url='/login/')
#user_passes_test(user_type_combo)
def change_employee_photo(request, pk):
data = dict()
profile = get_object_or_404(Profile, pk=pk)
if request.method == 'POST':
form = EmployeePhotoForm(request.POST or None, request.FILES or None, instance=profile)
if form.is_valid():
newPic = profile(emp_photo=request.FILES['emp_photo'])
newPic.save()
data['is_valid'] = True
else:
form = EmployeePhotoForm(instance=profile)
data['form_is_valid'] = False
context = {
'form': form,
}
data['html_form'] = render_to_string('employees/partial_employee_photo.html',
context,
request=request
)
return JsonResponse(data)
forms.py
class EmployeePhotoForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['emp_photo',]
{% load crispy_forms_tags %}
<form action="{% url 'change_employee_photo' form.instance.pk %}" class="js-change-employee-photo-form"
enctype="multipart/form-data" id="ProfileUpdateForm" method="post" runat="server">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title">Change Employee Photo</h5>
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group col">
<div id="emp_photo_holder">
<img alt="{{profile.first_name}}_{{profile.last_name}}" height="200px" id="emp_img"
src="/media/default.jpg/" width="200px"/>
<input id="emp_photo" name="emp_photo" type="file" value="{{profile.emp_photo}}"/>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#emp_img').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
$("#emp_photo").change(function() {
readURL(this);
});
</script>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" type="button">Close</button>
<button class="btn btn-warning confirmation"
onclick="return confirm('Are you sure you want upload a new photo for this employee?')"
type="submit">
<i class="fa fa-upload"></i> Upload
</button>
</div>
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
I will most definitely appreciate any help to have this issue resolved.
i Guess you have forgot to mention the below lines in your settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
You can think of using request.FILES.getlist('emp_photo')
and additionally check if emp_photo key exists by printing it in your code if it holds some value.
I'm trying to use modal as a edit form but I don't know good way.
Currently my views.py is like this.
def edit_entry(request, entry_pk):
entry = get_object_or_404(Entry, pk=entry_pk)
if request.method != 'POST':
form = EntryForm(instance=entry, user=request.user)
else:
form = EntryForm(instance=entry, data=request.POST, user=request.user)
if form.is_valid():
form.save()
and I have a template for this view.
What I want to do is
from the page that lists a bunch of entry objects, the edit form for the object is shown when I click edit button.
{% for entry in entries %}
...
<button class="btn btn-outline-primary" data-toggle="modal" data-target="#editEntryModal">Edit</button>
<!-- modal for the object -->
Anyone who could give me tips?
You need to send back your form as html and stick it in the modal before you show it. so on click, you would first do you ajax request, and this will send back your form as html. For example,
def edit_entry(request, entry_pk):
....
entry = get_object_or_404(Entry, pk=entry_pk)
if request.method != 'POST':
form = EntryForm(instance=entry, user=request.user)
return HttpResponse(form.as_p()) # This will return the plain html of a form
....
Hope this helps!
I had a similar task and first created an ajax request from the template to load the data:
<script>
$(document).ready(function(){
$("#myBtn").click(function(){
var pk = $(this).data('pid')
$("#myModal").modal("show");
});
$("#myModal").on('show.bs.modal', function(event){
var modal = $(this)
var pk = $(this).data('pid')
$.ajax({
data: {'pk': pk},
url: "{% url 'search:load_paper' %}",
context: document.body,
error: function(response, error) {
alert(error);
}
}).done(function(response) {
modal.html(response);
});
});
});
</script>
The load_paper function looks like the following:
def load_paper(request):
pk = request.GET.get('pk')
object = get_object_or_404(Paper, pk = pk)
form = PaperForm(instance=object)
return render(request, 'edit_paper_modal.html', {
'object': object,
'pk': pk,
'form': form,
})
The data is rendered in the 'edit_paper_modal.html', which looks like this:
<div class="modal-dialog modal-lg" role="document">
<form action="{% url 'search:edit_paper' pk=object.pk %}" method="post" class="form" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Edit Paper</h4>
</div>
<div class="modal-body">
{% csrf_token %}
{{form|crispy}}
{{ form.media }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Save changes" />
</div>
</div><!-- /.modal-content -->
</form>
</div>
The key thing here is that I am passing the pk of the paper back to the edit_paper function in views.py which actually saves the form.
Hope this is useful!
what you are trying to possible only with django template.
you need js or jquery or any frontend framework .
when you click edit button A edit from will appeared in current dom and you need to make ajax call to get initial data for edit from. the edit the data and submit the data vai ajax and in backend update the object. django rest framework is more suitable for this kind of task.