Ajax POST not sending data when calling 'request.POST' in Django view - javascript

I am attempting to get an Ajax POST to to send data to my view so I can manipulate my data there, when I click on a div with class up-arrow.
Problem is, when I click said div and print request.POST in my view file, I am getting a POST object that contains <QueryDict: {}>. Empty! I can't seem to figure out why my the POST request isn't sending my data through.
Here is my HTML...
{% for i in post.posts %}
<li>
<div>
<div class='up-arrow'>
</div>
{{i}}
</div>
</li>
{% endfor %}
Here is my AJAX/jQuery...
$(document).ready(function(){
$('.up-arrow').click(function(){
$(this).hide()
console.log('click')
$.ajax({
headers: {
'Content-Type':'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
url: 'voteuppost',
type: 'POST',
data: {'dane': 123456789101112},
success: function(data) {
alert('success!')
},
error: function(){
alert('fail')
}
})
return false
});
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]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
})
Here is my view...
class VoteUpPost(View):
def post(self, request):
print(request.POST)
return JsonResponse({'status': True})
Here is my url route...
url(r'^voteuppost$', VoteUpPost.as_view()),
Things I have tried...
1) I used GET instead of POST and I am able to get the data value using request.GET.get('dane')
1) Tried using request.POST.data and request.POST.DATA and get the following... AttributeError: 'QueryDict' object has no attribute 'data'
and I also get a 'fail' alert.
How do I send my data over to my view via a POST request and then access the data within?

When posting JSON data with application/json you need to use request.body instead of request.POST.
Like so:
class VoteUpPost(View):
def post(self, request):
print(request.body)
data = json.loads(request.body)
return JsonResponse({'status': True})
Also as Jacques mentioned, make sure to update your js to pass a JSON string.
Change:
data: {'dane': 123456789101112},
To:
data: JSON.stringify({'dane': 123456789101112}),

Django request can only parse application/x-www-form-urlencoded and
multipart/form-data to request.POST. For other content types you have to use request.body property. for assertion of content type you can get the content type from request.META.get('CONTENT_TYPE')
def sample_view(request):
if request.META.get('CONTENT-TYPE') == 'application/json':
data = json.loads(request.body)
return JsonResponse({'any-message':'Hello'})

Related

How to call Django API with Javascript with Authenticated user in Django

I'm using Django for Backend, PostgresSQL as DB and HTML, CSS and Javascript as Frontend. I am calling Django API via Javascript. Where user is adding a product to a cart, and I'm calling the cart with DRF to show all the data to the user. But problem is that, user can see all the data of other user. So, how can authenticated user can see his/her selected product on a cart.
Here is a detailed code:
views.py
adding product to cart
def addProduct(request):
user = request.user
product_id = request.GET.get('product_id')
product_cart = Product.objects.get(id=product_id)
Cart(user=user, product=product_cart).save()
return render(request, 'cart/addtocart.html')
Api View (views.py)
#api_view(['GET'])
def showproduct(request):
if request.method == 'GET':
result = Cart.objects.all()
serialize = productserializers(result, many = True)
return Response(serialize.data)
serializer.py
from .models import *
from rest_framework import serializers
class productserializers(serializers.ModelSerializer):
class Meta:
model = Cart
fields = '__all__'
depth = 1
Javascript to call Django API
$(document).ready(function() {
$.ajax({
url: 'http://127.0.0.1:8000/showproduct/',
dataType: 'JSON',
success: function(data){
for (var i = 0; i < data.length; i++)
{
var row =
$('<tr> .. ..........</tr>');
$("#table").append(row);
}
}
});
});
NOW, How to show the specific user(authenticated user) there specific cart item.
you have to pass user id when you are calling ajax.
If you are using GETmethod than pass user id in URL and access it via argument in your view for eg.
$(document).ready(function() {
$.ajax({
url: '{% url "showdata" %}',
dataType: 'JSON',
success: function(data){
for (var i = 0; i < data.length; i++)
{
var row =
$('<tr> .. ..........</tr>');
$("#table").append(row);
}
}
});
});
and in your views.py
#api_view(['GET'])
def showproduct(request):
if request.method == 'GET':
result = Cart.objects.filter(user=request.user)
serialize = productserializers(result, many = True)
return Response(serialize.data)
and add this in your urls.py
urlpatterns = [
path("showdata/", views.showproduct, name='showdata')
]
UPDATE
there is no need to pass user id in ajax URL if user is authenticated than user will come in request
so please change you views.py, urls.py and ajax URL.

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.

Bad request error in Flask while request names generated with javascript

I'm creating an app to calculate a projection of the transit given the years and some other values, first I created a script in javascript where depending on if the user decide to add a new type of vehicle a new div is created with unique ids and names and ofcourse the data the user introduced, for showing the final result i'm using ajax, the problem comes when i tried to access the data via flask, i'm getting a bad request from the names of each vehicle like if they did not exist, but the page is actually displaying them (hope you understand my english and my problem :) )
I've tried giving a specific name (a1) an then tried to take the value in flask but i still can#t make it work.
Python
#app.route("/pavimentos/calculoTransito" , methods=['POST'])
def calculoTransito():
direc = float(request.form["direc"])
zr = float(request.form["zr"])
years = float(request.form["years"])
tc = float(request.form["direc"])
vehicles = int(request.form["vehicles"])
car1 = request.form.get("a1", None)
if car1==None:
print("No funciona")
else:
print("Funciona")
always get "No funciona"
Javascript
countClicks = 0
lista_vehiculos = []
function addVehicle(){
countClicks += 1;
//var automovil = document.getElementById("automovil").value
var fd = document.getElementById("damage_factor").value
var currentType = document.getElementById("vehicleType")
if(currentType.value == 1){
var icon = "<h2 class='pt-4'><i class='fas fa-car text-secondary'></i></h2>";
var tipoVehiculo = "Automóvil";
}
... More code for select the currentType ...
var vehicleStyle = "<div><input id=a" + countClicks + "name=a" + countClicks + "value=" + fd + "></div>"
lista_vehiculos.push(vehicleStyle)
var vehicle = document.getElementById("vehiclesContainer").innerHTML += lista_vehiculos[countClicks-1]
document.getElementById("vehicles").value = countClicks
}
AJAX part
$(document).ready(function(){
$('form').on('submit', function(event){
$.ajax({
data:{
direc: $('#direc').val(),
zr: $('#zr').val(),
years: $('#years').val(),
tc: $('#growingRate').val(),
vehicles: $('#vehicles').val(),
car1: $('#a1').val()
},
type: 'POST',
url: '/pavimentos/calculoTransito'
})
.done(function(data){
if (data.resultado){
$('#resultado').text(data.resultado).show()
}
})
event.preventDefault();
});
});
You're not submitting a form, you're sending JSON. The initial event might be the submission of a form, but your AJAX uses event.preventDefault() and does not end up submitting a traditional serialized form. You can't use car1 = request.form.get("a1", None) here.
Firstly, you should correct your AJAX to add a contentType:
$(document).ready(function(){
$('form').on('submit', function(event){
$.ajax({
data: JSON.stringify({
direc: $('#direc').val(),
zr: $('#zr').val(),
years: $('#years').val(),
tc: $('#growingRate').val(),
vehicles: $('#vehicles').val(),
car1: $('#a1').val()
}),
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: '/pavimentos/calculoTransito'
})
.done(function(data){
if (data.resultado){
$('#resultado').text(data.resultado).show()
}
})
event.preventDefault();
});
});
And then you need to change your Flask method from request.form to request.json. So the Flask side would look something like:
#app.route("/pavimentos/calculoTransito" , methods=['POST'])
def calculoTransito():
req = request.json
direc = float(req["direc"])
zr = float(req["zr"])
...
car1 = req.get("a1", None)
if car1 is None: # None is a singleton, you shouldn't use == here
print("No funciona")
else:
print("Funciona")
LATE EDIT
This can't work because calculoTransito does not actually return anything, so Flask will throw an error from that alone. Your view function actually has to return something other than an implicit None.

how to use ajax function to send form without page getting refreshed, what am I missing?Do I have to use rest-framework for this?

I'm trying to send my comment form using ajax, right now when user inserts a comment then whole page gets refreshed. I want this to be inserted nicely without page getting refreshed.
So I tried bunch of things but no luck. since I'm a beginner, I tried to follow many tutorial links;
https://realpython.com/blog/python/django-and-ajax-form-submissions/
https://impythonist.wordpress.com/2015/06/16/django-with-ajax-a-modern-client-server-communication-practise/comment-page-1/#comment-1631
I realize my problem is that I have a hard time manipulating my code in views.py and forms.py
Thus before doing a client side programming(js and ajax) I need to set my backend(python code) again to be set for the ajax.
Can someone please help me with this?
I don't know how to set my backend....
<div class="leave comment>
<form method="POST" action='{% url "comment_create" %}' id='commentForAjax'>{% csrf_token %}
<input type='hidden' name='post_id' value='{{ post.id }}'/>
<input type='hidden' name='origin_path' value='{{ request.get_full_path }}'/>
{% crispy comment_form comment_form.helper %}
</form>
</div>
<div class='reply_comment'>
<form method="POST" action='{% url "comment_create" %}'>{% csrf_token %}
<input type='hidden' name='post_id' id='post_id' value='{% url "comment_create" %}'/>
<input type='hidden' name='origin_path' id='origin_path' value='{{ comment.get_origin }}'/>
<input type='hidden' name='parent_id' id='parent_id' value='{{ comment.id }}' />
{% crispy comment_form comment_form.helper %}
</form>
</div>
<script>
$(document).on('submit','.commentForAjax', function(e){
e.preventDefault();
$.ajax({
type:'POST',
url:'comment/create/',
data:{
post_id:$('#post_id').val(),
origin_path:$('#origin_path').val(),
parent_id:$('#parent_id').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success:function(json){
I don't know what to do here...I tried it but failing....what is going on here })
this is my forms.py
class CommentForm(forms.Form):
comment = forms.CharField(
widget=forms.Textarea(attrs={"placeholder": "leave your thoughts"})
)
def __init__(self, data=None, files=None, **kwargs):
super(CommentForm, self).__init__(data, files, kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
self.helper.add_input(Submit('submit', 'leave your thoughts', css_class='btn btn-default',))
and my views.py
def comment_create_view(request):
if request.method == "POST" and request.user.is_authenticated() and request.is_ajax():
parent_id = request.POST.get('parent_id')
post_id = request.POST.get("post_id")
origin_path = request.POST.get("origin_path")
try:
post = Post.objects.get(id=post_id)
except:
post = None
parent_comment = None
if parent_id is not None:
try:
parent_comment = Comment.objects.get(id=parent_id)
except:
parent_comment = None
if parent_comment is not None and parent_comment.post is not None:
post = parent_comment.post
form = CommentForm(request.POST)
if form.is_valid():
comment_text = form.cleaned_data['comment']
if parent_comment is not None:
# parent comments exists
new_comment = Comment.objects.create_comment(
user=MyProfile.objects.get(user=request.user),
path=parent_comment.get_origin,
text=comment_text,
post = post,
parent=parent_comment
)
return HttpResponseRedirect(post.get_absolute_url())
else:
new_comment = Comment.objects.create_comment(
user=MyProfile.objects.get(user=request.user),
path=origin_path,
text=comment_text,
post = post
)
return HttpResponseRedirect(post.get_absolute_url())
else:
messages.error(request, "There was an error with your comment.")
return HttpResponseRedirect(origin_path)
else:
raise Http404
I'm still very shaky on the idea of using ajax even after reading a tutorial about it...how json comes into play and how I should modify views.py too....can someone please explain how they all group together?and help me getting this done...
else:
raise Http404
see official document of submit() and serialize() and modify your ajax all like this :
<script>
$('#commentForAjax' ).submit(function(e){
e.preventDefault();
$.ajax({
type:'POST',
url:'comment/create/', // make sure , you are calling currect url
data:$(this).serialize(),
success:function(json){
alert(json.message);
if(json.status==200){
var comment = json.comment;
var user = json.user;
/// set `comment` and `user` using jquery to some element
}
},
error:function(response){
alert("some error occured. see console for detail");
}
});
});
At backend side you are returning HttpResponseRedirect() which will redirect your ajax call to some url(status code=302). I will suggest to return any json response.
For Django 1.7+ add line from django.http import JsonResponse to return json response
For pre Django 1.7 use return HttpResponse(json.dumps(response_data), content_type="application/json")
Modify this portion of your views.py to return Json response
def comment_create_view(request):
# you are calling this url using post method
if request.method == "POST" and request.user.is_authenticated():
parent_id = request.POST.get('parent_id')
post_id = request.POST.get("post_id")
origin_path = request.POST.get("origin_path")
try:
post = Post.objects.get(id=post_id)
except:
# you should return from here , if post does not exists
response = {"code":400,"message":"Post does not exists"}
return HttpResponse(json.dumps(response), content_type="application/json")
parent_comment = None
if parent_id is not None:
try:
parent_comment = Comment.objects.get(id=parent_id)
except:
parent_comment = None
if parent_comment is not None and parent_comment.post is not None:
post = parent_comment.post
form = CommentForm(request.POST)
if form.is_valid():
comment_text = form.cleaned_data['comment']
if parent_comment is not None:
# parent comments exists
new_comment = Comment.objects.create_comment(
user=MyProfile.objects.get(user=request.user),
path=parent_comment.get_origin,
text=comment_text,
post = post,
parent=parent_comment
)
response = {"status":200,"message":"comment_stored",
"user":new_comment.user,
"comment":comment_text,
}
return HttpResponse(json.dumps(response), content_type="application/json")
else:
new_comment = Comment.objects.create_comment(
user=MyProfile.objects.get(user=request.user),
path=origin_path,
text=comment_text,
post = post
)
response = {"status":200,"message":"new comment_stored",
"user":new_comment.user,
"comment":comment_text,}
return HttpResponse(json.dumps(response), content_type="application/json")
else:
messages.error(request, "There was an error with your comment.")
response = {"status":400,"message":"There was an error with your comment."}
return HttpResponse(json.dumps(response), content_type="application/json")
You don't have to use rest-framework. But if you use rest-framework for this purpose , it will be easy to implement.
This is general structure of your comment app. I am assuming you are using Django REST Framework
- Comment
- models.py
- forms.py
- views.py
Comment Model (models.py)
from django.db import models
class Comment(models.Model):
user = models.ForeignKey(MyProfile)
post = models.ForeignKey(Post)
parent = models.ForeignKey("self")
text = models.TextField()
path = ...
...
Comment Form (forms.py)
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('text', 'post_id', 'parent_id')
post_id = forms.HiddenInput()
parent_id = forms.HiddenInput()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['text'].label = _('Comment')
self.fields['post_id'].value = self.instance.post.id
self.fields['parent_id'].value = self.instance.parent.id
self.helper = FormHelper()
self.helper.form_show_labels = False
self.helper.layout = Layout(
ManageFieldsWrapper(
crispy_fields.Field('text')
),
crispy_fields.SubmitField(submit_label='Leave your thoughts')
)
Comment form view and api view (views.py)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import HttpResponseRedirect
from django.views.generic.edit import CreateView
from .forms import CommentForm
from .models import Comment
class CommentFormView(CreateView):
form_class = CommentForm
class CommentAPISubmitView(APIView):
def post(self, request, format=None):
#... Your checks goes here ...
form = CommentForm(request.POST or None)
if form.is_valid():
#... Your saving logic here ..
return HttpResponseRedirect(redirect_url)
else:
return HttpResponseRedirect(origin_path)
return Response(status=status.HTTP_400_BAD_REQUEST)
Finally client side code AJAX/JQuery
$(document).ready(function() {
$("#commentForAjax").submit(function( event ) {
$.ajax({
type:'POST',
url:'comment/create/',
data:{
post_id:$('#post_id').val(),
origin_path:$('#origin_path').val(),
parent_id:$('#parent_id').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success: function(response){
}
});
event.preventDefault()
});
});
As per your current code It seems like it will always get redirect because after validating the comment form and updating it into database you are returning HttpResponseRedirect which is designed to redirect.
I think what you want is to update the comment into database and get a success response.
So to achieve this you need to change the response type, I would suggest return JsonResponse and based on the json response you can update the html as well, I am sure returning json response won't cause redirect your html.
Let me know if it's clear to you.
Thanks.
After completely reviewing your code and discussing with OP in length. I've managed to resolve the OPs issue.
After removing HttpResponseRedirect I first converted it to JsonResponse and made changes accordingly.
response_data = {
"status":200, "message":"comment_stored",
"parent": True,
"parent_id": parent_comment.id,
"comment_count": parent_comment.comment_count()
}
return JsonResponse(response_data)
Next step was to simply perform DOM manipulation to display the data fetched from the response. But turns out this was more complicated than expected. So, to simplify it I simply separated the template into 2 parts - one will be the main part and the other containing the HTML of only the comment.
Using django.template.loader.render_to_string I generated the required HTML to display the comment and sent with the response as a string in JSON.
html = render_to_string('main/child_comment.html',
{'comment': [new_comment],
'user': request.user,
'comment_form':comment_form
})
response_data = {
"status":200, "message":"comment_stored",
"comment":html,
"parent": True, "parent_id": parent_comment.id,
"comment_count": parent_comment.comment_count()
}
return JsonResponse(response_data)
Finally, after minor changes (not relevant to the current issue) mainly in the DOM manipulation scripts and in one of the form models, the code worked as expected.
$('form').submit(function(e) {
e.preventDefault();
if ($(this).parents("tr") != 0) {
parent_id = $(this).parents("tr").attr("id").split("_")[1];
data_str = $(this).serialize() + "&parent_id=" + parent_id;
} else {
data_str = $(this).serialize();
}
$(this).parents("tr").attr("id").split("_")[1]
$.ajax({
type: 'POST',
url: '{% url 'comment_create' %}',
data: data_str,
success: function(json) {
alert(json.message);
if (json.status == 200) {
var comment = json.comment.trim();
var user = json.user;
if (!json.parent) {
$(comment).insertBefore('.table tr:first');
} else {
$(comment).insertBefore('#comment_' + json.parent_id + ' #child_comment:first');
$(".replies").text("답글" + json.comment_count + "개 모두 보기");
}
}
},
error: function(response) {
alert("some error occured. see console for detail");
}
});
});
BONUS: There was another minor issue which we had faced but I won't discuss it here. I've written a separate answer for it.
The main thing you need to do for preventing page reloading on form submit is calling event.preventDefault() in your form submit event handler.
#Vibhu provided a very good code example in the answer above. That's exactly what you need to do on client side. (I provide his code with a single difference, request is sent to 'comment/create-ajax', not to 'comment/create'
$(document).ready(function() {
$("#commentForAjax").submit(function( event ) {
$.ajax({
type:'POST',
url:'comment/create-ajax',
data:{
post_id:$('#post_id').val(),
origin_path:$('#origin_path').val(),
parent_id:$('#parent_id').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success: function(response){
}
});
event.preventDefault()
});
});
On server side, you may provide one more controller (view in Django terms) which handles POST /comments/create-ajax, it should look somehow like this:
def handle_comment_creation_via_ajax(request):
comment_dict = json.loads(request.body)
# or json.loads(request.body.decode("utf-8")) if you use python 3
comment = CommentModel(**comment_dict) # This will work if comment has no nested models, otherwise, implement static method in your model class which takes dict and returns model instance.
try:
comment.save()
except Exception as e:
return JsonResponse({'success':false, 'message': str(e)}, status_code=400)
return JsonResponse(model_to_dict(instance, fields=[], exclude=[])
JsonResponse and model_to_dict
Good luck!
P.S. Note that incoming model must be validated before save
For the sake of example, I would like to show how to achieve this using Django REST Framework and how much code you DON'T need to change.
TL;DR
Installing DRF doesn't break anything. Just add 8 lines of code (without imports), change 2 existing lines and get rid of your entire comment_create_view.
For those who are interested in more details, please read further.
1. Install django-rest-framework using this guide.
2. Create a serializers.py file with the following contents
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__' # or specify the list of fields you want to be present
Here you define the class that will serialize (transform a Comment model instance to a json object) and deserialize (inverse action of transforming a json object into a Comment instance) your comments.
3. Add the following view to your views.py
from rest_framework.generics import CreateAPIView
class CommentCreateView(CreateAPIView):
queryset = Comments.objects.all()
serializer_class = CommentSerializer
Note: These 4 lines of code actually substitute your whole comment_create_view.
Here you define a generic view designed specifically for creation of objects. CreateAPIView will handle only POST requests and will use the CommentSerializer class to convert objects. A serializer class to Django REST framework is what a form class is to Django - it handles the validation of data and returns a response in form of json, or corresponding error messages (also in json) in case your data is not correct.
4. Add the following to your main urls.py file
url_patterns = [
... # your urls here
url(r'^api/v1/comments/$', CommentCreateView.as_view(), name='comments-list')
]
Here you register your API view as a route to which you can send requests.
5. Edit your ajax request
$.ajax({
type:'POST',
url:'api/v1/comments/', // switch to the API view url
contentType: 'application/json', // tell ajax to send it as `json` content
data:{
post_id:$('#post_id').val(),
origin_path:$('#origin_path').val(),
parent_id:$('#parent_id').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success:function(json){
You POST to the newly created API endpoint data in form of json and your serializer takes it and creates a Comment model instance from it that is saved to the database. In case you need some specific behavior while creating a Comment (or any other model) instance, you can override the .create() method of your CommentSerializer. For more details check the Django REST framework tutorial.
6. Do whatever you need with the newly created comment
This part applies to non Django REST framework scenarios as well. Once you've successfully created the comment, in your success function you will receive it in json form and depending on what you want to do with it, you need to define the desired behavior in this success function.
Basically that's it. Please take into account that the example described here is a minimal required code to make it work for you. I've used the out-of-the-box Django REST framework features, but of course it has many more possibilities to make things work. Maybe you'll need to override some default methods, but in the end, because DRF is designed to deal with ajax calls, your code will be shorter and cleaner.
Good luck!
This is the easiest example of how to implement Ajax forms in conjunction with Django:
You can use Ajax Post to send JSON to Django and then handle the arguments as a dict(). Here is an example:
In browser (JQuery/JavaScript):
function newModule() {
var my_data = $("#my_element").val(); // Whatever value you want to be sent.
$.ajax({
url: "{% url 'modules' %}", // Handler as defined in Django URLs.
type: "POST", // Method.
dataType: "json", // Format as JSON (Default).
data: {
path: my_data, // Dictionary key (JSON).
csrfmiddlewaretoken:
'{{ csrf_token }}' // Unique key.
},
success: function (json) {
// On success do this.
},
error: function (xhr, errmsg, err) {
// On failure do this.
}
});
In server engine (Python):
def handle(request):
# Post request containing the key.
if request.method == 'POST' and 'my_data' in request.POST.keys():
# Retrieving the value.
my_data = request.POST['my_data']
# ...
If the form is submitting it is not your backend code but your javascript code, you need to prevent the form from submitting, you can try changing this:
<script>
$(document).on('submit','.commentForAjax', function(e){
e.preventDefault();
To this:
<script>
$(document).ready(function(){
$("#comentForAjax").submit(function(e){
e.preventDefault();
// Do whatever you need to do, like serializing the form and post with $.ajax
});
});
So make sure you are binding the submit event right after the document loads so the browser knows that the form should not be submitted, and then you just make your ajax call and do whatever you need with the returned serialized data from the server.
Again, if the form is posting, it doesn't have anything to do with the backend code.
Note: For jquery selectors, if you need to select something by id you use the #element hash sign and if you want to target class selectors then you use the dot notation .elements. Also note that you can in theory select just one element by ID (given that you don't duplicate the ID for other elements) but classes are usually used to span several elements that share the same attributes.
In your javascript, you call for the class .commentForAjax.
You should call the ID:
$(document).on('submit','#commentForAjax', function(e){
// ...
});
Hope this helps.
R
In your form tag below
<form method="POST" action='{% url "comment_create" %}' id='commentForAjax'>{% csrf_token %}
You don't need to define action or method. You handle them via ajax. So delete them and you form won't try to execute that action.And hopefully it will solve your refresh page issue.Also change your on submit line '.commentForAjax' into '#commentForAjax' since it is not a class but id.
$(document).on('submit','.commentForAjax', function(e){
e.preventDefault();
// Put
e.stopPropagation();

Django - AJAX Request returns 500 INTERNAL SERVER ERROR

I am trying to simply update a boolean form value by using an ajax function to update it, because why would I want it to reload, but anyways, I have checked that I am passing the csrf_token, and made sure that's not a problem. I was thinking it was a problem with my urls.py, but I'm not sure exactly what it is.
What can I do to fix this error?
heres my views.py for the ajax form, note: project_complete is a booleanfield in my model
#login_required
def ProjectDetailToDoCForm(request):
form = ProjectToDoCForm(request.POST or None)
if form.is_valid() and request.is_ajax():
args = {}
args.update(csrf(request))
ajaxVal = request.POST.get('booleanValue')
args['doneBool'] = ajaxVal.project_complete
return HttpResponse(json.dumps(args), content_type="application/json")
javascript
<script type="text/javascript">
$(document).on("submit", "#project_edit_date", function(e){
e.preventDefault();
updateForm();
});
function updateForm() {
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]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
$.ajax({
url: "{% url 'projects:todoc_form' %}",
type: "POST",
datatype: "json",
data: {booleanValue : $("#id_project_complete").val()},
"beforeSend": function(xhr, settings) {
console.log("Before Send");
$.ajaxSettings.beforeSend(xhr, settings);
},
success: function(json){
console.log(json);
console.log("success");
},
error:function(xhr,errmsg,err){
console.log(err);
}
});
}
</script>
form
<form action="" method="post" id="project_edit_date">{% csrf_token %}
<label for="todoc">Task Done?</label>
<span name="todoc" id="check_done"> {{todocform.project_complete}}</span>
<button type="submit" id="project_edit_button">
<span>Update</span>
</button>
</form>
urls.py
urlpatterns = patterns('',
url(r'^$', views.ProjectView.as_view() , name='project'),
url(r'^create/$', views.createproject, name='create'),
url(r'^edit/(?P<slug>[\w-]+)/$', views.ProjectDetail.as_view(), name='indproject'),
url(r'^view/(?P<slug>[\w-]+)/$', views.ProjectDetailPublic.as_view(), name='pproject'),
url(r'^form/(?P<slug>[\w-]+)/$', require_POST(ProjectDetailForm.as_view()), name='indproject_form'),
url(r'^update/(?P<slug>[\w-]+)/$', require_POST(ProjectDetailToDoForm.as_view()), name='todo_form'),
url(r'^complete/$', ProjectDetailToDoCForm, name='todoc_form'),
)
Just a general tip as you have posted all the code including HTML / JS / Python / urls.py ...
If you have an error in your JS (Client side error) you will see it in the browser log (console).
If there is an error in urls.py you will most likely get an HTTP Response 404 Not Found meaning the URL couldn't be resolved.
If you get a HTTP Response 500 Internal Server Error this most certainly means you have a server error (runtime error in your python code /views.py/.
In general read the most frequent response codes and what they mean here HTTP/1.1: Status Code Definitions

Categories