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
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.
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.
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
$(document).on('submit','.commentForAjax', function(e){ e.preventDefault();
// Put
e.stopPropagation();
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.
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.
django-rest-framework
using this guide.serializers.py
file with the following contentsclass 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.
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.
urls.py
fileurl_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.
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.
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!