An Easy way to submit Django Forms using Ajax jQuery
Solution 1
The AJAX
concept is not a lot different from how a general form submissions work. The idea behind AJAX is to have submit(pass) the data to the server asynchronously.
How it works?
With a general form submission the flow goes somthing like this.
User submits a POST request
↓
Server Does the Data Processing
↓
Redirects to a Success or Failure Page
With ajax it works pretty similar.
User Submits a form through AJAX
↓
AJAX sends the POST data to the server in the background and waits for a response
↓
Server does the Data Processing
↓
and sends a Response back to AJAX
↓
AJAX sends the response back to the same template where the request was initiated.
Now let's have a look at a simple Ajax Login with a django view.
views.py
def ajax_login(request):
"""
This view logs a user in using the POST data.
"""
if request.method == 'POST':
data = {}
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if (not user is None) and (user.is_active):
login(request, user)
# Set Session Expiry to 0 if user clicks "Remember Me"
if not request.POST.get('rem', None):
request.session.set_expiry(0)
data['success'] = "You have been successfully Logged In"
else:
data['error'] = "There was an error logging you in. Please Try again"
return HttpResponse(simplejson.dumps(data), mimetype="application/json")
In the above view , we did the data processing and sent a JSON response back. The ajax method will look something like this.
function ajaxLogin(){
var dataString = '&username=' + $('input[name=username]').val() +
'&password=' + $('input[name=password]').val() +
$.ajax({
type: "POST",
url: "/ajax_login/",
data: dataString,
success: function(data) {
alert(data);
}
});
return false;
}
Here, the success method recieves the data back and alerts
it to the user.
UPDATE
I see that you have defined the ajaxPwchange()
method but i do not really see you calling it anywhere and i think that is why the page still refreshes. You can bind the ajaxPwchange()
method to submit button's onclick
event as follows.
<input class="btn btn-primary" type="submit" value="submit" onclick="ajaxPwchange();" />
or bind it under the document.ready
method as follows:
$(document).ready(function(){
$('input.btn-primary').click(function(){
ajaxPwchange();
});
});
UPDATE2
The div disappears because you are changing the div's html
to a json
object directly in the following code.
success: function(response) { // on success..
$('#modalchangepw').html(response); // update the DIV
}
you should rather try something like this :
success: function(response) { // on success..
var jsonData = $.parseJSON(response);
$.each(response, function(){
$('#modalchangepw').append('<div class="message">' + $(this) + '</div>');
});
}
Solution 2
I'll give you a very easy example so that you can grasp the concept and then use that same concept to do what you're trying to do.
I would start by creating a normal view in views.py
def MyAjaxView(request):
if request.is_ajax():
if request.method == 'GET':
# If it was a GET
print request.GET
elif request.method == 'POST':
# Here we can access the POST data
print request.POST
else:
doSomeOtherStuff()
return render_to_response('mytemplate.html', some_context_maybe, context_instance=RequestContext(request))
Depending on what you already use or what you are allowed to use you would call this using javascript or the library jQuery.
Assuming you have a form that looks like this
<form id="myNameForm">
{% csrf_token %}
<input type="text" id="name" />
<input type="submit" value="submit" id="submitButton" />
</form>
you can now hook this up to an ajax function using JavaScript, I'll be using jQuery as demonstration and I'll use the jQuery method ajax()
as it explains the concept and moving on to post()
shouldn't be all too difficult.
<script>
$('#submitButton').click(function(event){
event.preventDefault(); //so that we stop normal form submit.
$.ajax(
url: 'myViewUrl',
type: 'post',
dataType: 'json',
data: $('form#myNameForm').serialize(),
success: function(data) {
doStuffWithDataHere(data);
}
);
});
</script>
You have to make sure that your urls.py
have a url mapping to your new view.
Using the CSRF protection also requires to use the CSRF processor, see BurhanKhalids comment for documentation.
Jonathan
Updated on July 05, 2022Comments
-
Jonathan almost 2 years
I am relatively new to Ajax and I am still trying to grasp all the concepts. I've tried to look into a bunch of tutorials for Ajax-Django form submission, most of them require jQuery forms, which doesn't seem like an easy way to handle form submission to me. I am having a hard time grasping the concept.
I am trying to write some ajax based form submissions for user registration, login, post creation and comments. And so far I havent found a way that makes it easier for me to understand how the Ajax approach would work.
I would really appreciate any help that I can get in this regard.
This is what I've tried so far.
change_pw.html
{% extends "base.html" %} {% block title %}Change Password{% endblock %} {% block head %}Change Password{% endblock %} {% block content %} {% include "modal_change_pw.html" %} {% endblock %}
modal_change_pw.html
<div id="modalchangepw"> <ul style="margin:5px;"> <ul class="thumbnails" style="margin: 0 auto;background: white;"> <div class="thumbnail row-fluid" style="background: white; padding: 10px;width: 97%; -moz-border-radius: 5px;border-radius: 5px;-moz-box-shadow:3px 3px 5px 0px #ccc;-webkit-box-shadow:3px 3px 5px 0px #ccc;box-shadow:3px 3px 5px 0px #ccc;"> <br> {% if not error == '' %} <div class="alert alert-error"> <button type="button" class="close" data-dismiss="alert">×</button> {{ error }} </div> {% endif %} {% if not success == '' %} <div class="alert alert-success"> <button type="button" class="close" data-dismiss="alert">×</button> {{ success }} </div> {% endif %} {% if messages %} {% for message in messages %} <div{% if message.tags %} class="alert alert-{{ message.tags }}"{% endif %}> <button type="button" class="close" data-dismiss="alert">×</button> {{ message|safe }} </div> {% endfor %} {% endif %} <form id = 'changepw' enctype="multipart/form-data" method="post" action="."> <p><label for="id_currentpw">Current Password:</label> <input type="password" name="currentpw" id="id_currentpw" /></p> <p><label for="id_newpw1">New Password:</label> <input type="password" name="newpw1" id="id_newpw1" /></p> <p><label for="id_newpw2">Re-enter New Password:</label> <input type="password" name="newpw2" id="id_newpw2" /></p> <input class="btn btn-primary" type="submit" value="submit"/> {% csrf_token %} </form> </div> </ul> </ul> </div>
views.py
def change_pw(request): user=request.user error='' success='' if request.method == 'POST': form = ChangePw(request.POST) if form.is_valid(): currentpw=form.cleaned_data['currentpw'] newpw1=form.cleaned_data['newpw1'] newpw2=form.cleaned_data['newpw2'] if currentpw and newpw1 and newpw2: if user.check_password(currentpw): if newpw1==newpw2: user.set_password(newpw1) user.save() success='Password updated!!' if request.is_ajax() : messages.success(request, 'Password updated.') return HttpResponseRedirect ('/changepw/') else: return HttpResponseRedirect ('/user/%s/' % user.username) else: error='New passwords do not match' else: error='Incorrect Current Password' else: error='Enter all Password fields to make any changes' else: form = ChangePw() variables = RequestContext(request, { 'form':form, 'error':error, 'success':success }) if request.is_ajax() : return render_to_response('modal_change_pw.html', variables) else: return render_to_response('change_pw.html', variables)
forms.py
class ChangePw(forms.Form): currentpw = forms.CharField( label=u'Current Password', required=False, widget=forms.PasswordInput() ) newpw1 = forms.CharField( label=u'New Password', required=False, widget=forms.PasswordInput() ) newpw2 = forms.CharField( label=u'Re-enter New Password', required=False, widget=forms.PasswordInput() )
jQuery
//Change PW $('#changepw').live('submit', function(event) { // catch the form's submit event event.preventDefault(); $.ajax({ // create an AJAX call... data: $(this).serialize(), // get the form data type: $(this).attr('method'), // GET or POST url: $(this).attr('action'), // the file to call success: function(response) { // on success.. $('#modalchangepw').html(response); // update the DIV } }); return false; });
The code seems to work fine now. But my aim is to handle these forms in a modal popup fashion, so that the user doesn't have to leave the page he/she is currently on. In a modal-popup case, my form does not seem to be submitting the values.
-
Burhan Khalid over 11 yearsNo need for extra
()
around an if condition. Userender
to automatically pass inRequestContext
. Keep in mind that you must return aHttpResponse
from views. Simply printing stuff will lead to errors. Finally, you need to use csrf protection for POST requests. -
Henrik Andersson over 11 yearsAbsolutely! :) Thanks @BurhanKhalid I was just coding some java and the parens started to tag along! :) Sorry for that also thanks for the csrf_token, I had forgotten that.
-
Yuji 'Tomita' Tomita over 11 yearsI like the downward arrows, and the explanation.
-
Jonathan over 11 yearsI am sorry for not adding code earlier. I did not have any jQuery code as I was having a hard time understanding the concept. Based on the answers I did try adding an AJAX logic, but it doesn't seem to work
-
Jonathan over 11 years@Amyth thank you for your reply. Even the onclick and document ready approach did not work. I have updated the code to what seems to kind of work, please have a look
-
Amyth over 11 yearshey @Jonathan , i have added another update. please have a look.
-
Jonathan over 11 years@Amyth with the code you just updated, the form becomes unresponsive. The form does not submit. But I think I do have an idea why the Div disappears, but the main concern is that the form does not seem to work in a modal popup senario
-
Amyth over 11 yearsdo you the request being sent in the console while using modal popup ?
-
Jonathan over 11 years@Amyth Can you elaborate on that? I did not quite understand what you meant. I am updating the code, with the current code, the forms gets submitted just fine. But not in a modal popup setup still.
-
Amyth over 11 yearsSo, when you use a modal popup and hit the submit button, does the POST request is made ? To check this you can either use the
console
in a tool like firebug or just check the server log to see what was the last request that the server received. So my question was is the request being sent to the server when you are using the modal popup ? -
Jonathan over 11 years@Amyth yes a post request is made on [01/Jan/2013 01:50:36] "POST / HTTP/1.1" 200 8126 instead of [01/Jan/2013 01:50:54] "POST /changepw/ HTTP/1.1" 200 1424 (which is the usual case, in a non-modal senario)
-
Amyth over 11 yearsin that case make sure the
url
in$.ajax
while using modal popup is the correct url. It seems currently in the modal popup scenario the url that is being passed to the $.ajax function is an empty string (""
) and that's why the request is being sent to/
instead of/changepw/
-
Jonathan over 11 years@Amyth Thank you so much! that was a vary stupid mistake. now it works just fine! Thank you so much!
-
Love Putin almost 4 years@BurhanKhalid - One clarification please. Is it possible that I send the ajax request to a different view than the one used to render the form initially? To
POST
form data. -
Burhan Khalid almost 4 yearsYes of course. You can send the request to any view.
-
Love Putin almost 4 years@BurhanKhalid - Actually I am unable to do that. I have tried various ways to write a FBV to just do that, but sadly none of it seem to post the data. In console I can see the form data nicely serialized, but it's not posted to the DB. Could you please point me to a minimal example of how should the view look like for a
management_form
(parent/child) scenario? PS - Till I got to know from you, I had almost started to believe that sending ajax request to a different view toPOST
wasn't possible!! -
Love Putin almost 4 years@BurhanKhalid - Just tried a generic
CeateView
for a standalone model, but the data is not getting saved. Where as using the same concept I am able toPOST
data w/o ajax. (PS - I am pointing to the same template from where ajax request is being fired).