An Easy way to submit Django Forms using Ajax jQuery

23,102

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.

Share:
23,102
Jonathan
Author by

Jonathan

Updated on July 05, 2022

Comments

  • Jonathan
    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">&times;</button>
                        {{ error }}
                    </div>
                {% endif %}
                {% if not success == '' %}
                    <div class="alert alert-success">
                        <button type="button" class="close" data-dismiss="alert">&times;</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">&times;</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
    Burhan Khalid over 11 years
    No need for extra () around an if condition. Use render to automatically pass in RequestContext. Keep in mind that you must return a HttpResponse from views. Simply printing stuff will lead to errors. Finally, you need to use csrf protection for POST requests.
  • Henrik Andersson
    Henrik Andersson over 11 years
    Absolutely! :) 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
    Yuji 'Tomita' Tomita over 11 years
    I like the downward arrows, and the explanation.
  • Jonathan
    Jonathan over 11 years
    I 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
    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
    Amyth over 11 years
    hey @Jonathan , i have added another update. please have a look.
  • Jonathan
    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
    Amyth over 11 years
    do you the request being sent in the console while using modal popup ?
  • Jonathan
    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
    Amyth over 11 years
    So, 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
    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
    Amyth over 11 years
    in 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
    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
    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
    Burhan Khalid almost 4 years
    Yes of course. You can send the request to any view.
  • Love Putin
    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 to POST wasn't possible!!
  • Love Putin
    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 to POST data w/o ajax. (PS - I am pointing to the same template from where ajax request is being fired).