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.pyfrom 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.
commentThis 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!