Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
193 views

Django and AJAX Form Submissions - Say 'Goodbye' To The Page Refresh - Real Python

A tutorial about getting rid of the refresh page.

Uploaded by

Parse1234
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
193 views

Django and AJAX Form Submissions - Say 'Goodbye' To The Page Refresh - Real Python

A tutorial about getting rid of the refresh page.

Uploaded by

Parse1234
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

AUG 25TH, 2014 | COMMENTS

Django and AJAX Form Submissions Say 'Goodbye' to the Page Refresh
This is a collaboration piece between Real Python and the mighty Nathan Nichols, using a
collaborative method we have dubbed agile blogging`. Say hi @natsamnic
(http://twitter.com/natsamnic).

Lets get down to business:


1. Download the compressed pre-ajax Django Project from the repo
(https://github.com/realpython/django-form-fun/tree/master/part1)
2. Activate a virtualenv
3. Install the requirements
4. Sync the database
5. Fire up the server
Once logged in, test out the form. What we have here is a simple communication app with just
create rights. It looks nice, but theres one annoying issue: The page refresh. How do we get rid
of it? Or, how do we update just a portion of a webpage without having to refresh the entire
page? Enter AJAX. AJAX is a client-side technology used for making asynchronous requests to the
server-side i.e., requesting or submitting data where the subsequent responses do not cause
an entire page refresh.

https://realpython.com/blog/python/django-and-ajax-form-submissions/

1/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

This tutorial assumes you have working knowledge of Django as well


as some experience with JavaScript/jQuery. You should also be
familiar with the basic HTTP methods, particularly GET and POST. Need
to get up to speed? Get Real Python (http://realpython.com).

Use Protection
Regardless of whether youre using AJAX or not, forms are at risk for Cross Site Request Forgeries
(CSRF) attacks.

Read more about CSRF attacks on the Coding Horror


(http://blog.codinghorror.com/preventing-csrf-and-xsrf-attacks/) blog.
Theyve got a great article.
To prevent such attacks, you must add the {% csrf_token %} template tag to the form, which
adds a hidden input field containing a token that gets sent with each POST request.

https://realpython.com/blog/python/django-and-ajax-form-submissions/

2/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

If you look at the talk/index.html template, you can see that we have already included this token.
However, when it comes to AJAX requests, we need to add a bit more code, because we cannot
pass that token using a JavaScript object since the scripts are static.
To get around this, we need to create a custom header that includes the token to watch our back.
Simply grab the code here (https://gist.github.com/broinjc/db6e0ac214c355c887e5) and add it
to the end of the main.js file. Yes, its a lot of code. We could go through it line-by-line, but thats
not the point of this post. Just trust us that it works.
Moving on

Handling Events
Before we touch the AJAX code, we need to add an event handler
(http://learn.jquery.com/events/handling-events/) to our JavaScript file using jQuery.

Keep in mind that jQuery is JavaScript. Its simply a JavaScript library


used to reduce the amount of code you need to write. This is a
common area of confusion so just be mindful of this as you go through
the remainder of this tutorial.
Which event(s) do we need to handle? Since were just working with creating a post at this
point, we just need to add one handler to main.js:
1
2
3
4
5
6

// Submit post on submit


$('#post-form').on('submit', function(event){
event.preventDefault();
console.log("form submitted!") // sanity check
create_post();
});

Here, when a user submits the form this function fires, which1. Prevents the default browser behavior
(http://www.w3schools.com/jquery/event_preventdefault.asp) for a form submission,
2. Logs form submitted! to the console, and
3. Calls a function called create_post() where the AJAX code will live.
Make sure to add an id of post-form to the form on the index.html file:
1

<form action="/create_post/" method="POST" id="post-form">

And add a link to the JavaScript file to the bottom of the template:
https://realpython.com/blog/python/django-and-ajax-form-submissions/

3/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

<script src="static/scripts/main.js"></script>

Test this out. Fire up the server, then open your JavaScript console. You should see the following
when you submit the form:
1
2

form submitted!
Uncaught ReferenceError: create_post is not defined

This is exactly what we should see: The form submission is handled correctly, since form
submitted! is displayed and the create_post function is called. Now we just need to add that
function.

Adding AJAX
Lets develop one last iteration before we add the actual AJAX code.

Update main.js:
Add the create_post function:
1
2
3
4
5

// AJAX for posting


function create_post() {
console.log("create post is working!") // sanity check
console.log($('#post-text').val())
};

Again, we ran a sanity check to ensure the function is called correctly, then we grab the input
value of the form. For this to work correctly we need to add an id to the form field:

Update forms.py:
1
2
3
4
5
6
7
8
9
10

class PostForm(forms.ModelForm):
class Meta:
model = Post
# exclude = ['author', 'updated', 'created', ]
fields = ['text']
widgets = {
'text': forms.TextInput(
attrs={'id': 'post-text', 'required': True, 'placeholde
r': 'Say something...'}
),
}

https://realpython.com/blog/python/django-and-ajax-form-submissions/

4/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

Notice how we also added a placeholder to the field and made it required along with the id. We
could add some error handlers to the form template or simply let HTML5 handle it. Lets use the
latter.
Test again. Submit the form with the word test. You should see the following in your console:
1
2
3

form submitted!
create post is working!
test

Sweet. So, weve confirmed that were calling the create_post() function correctly as well as
grabbing the value of the form input. Now lets wire in some AJAX to submit the POST request.

Update main.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// AJAX for posting


function create_post() {
console.log("create post is working!") // sanity check
$.ajax({
url : "create_post/", // the endpoint
type : "POST", // http method
data : { the_post : $('#post-text').val() }, // data sent with
the post request
// handle a successful response
success : function(json) {
$('#post-text').val(''); // remove the value from the input
console.log(json); // log the returned json to the console
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' dat
a-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>&times;</a></div>"); // add
the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provi
de a bit more info about the error to the console
}
});
};

https://realpython.com/blog/python/django-and-ajax-form-submissions/

5/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

Whats happening? Well, we submit form data to the create_post/ endpoint, then wait for one
of two responses either a success or a failure. Follow the code comments for a more detailed
explanation.

Update the views


Now lets update our views to handle the POST request correctly:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

def create_post(request):
if request.method == 'POST':
post_text = request.POST.get('the_post')
response_data = {}
post = Post(text=post_text, author=request.user)
post.save()
response_data['result'] = 'Create post successful!'
response_data['postpk'] = post.pk
response_data['text'] = post.text
response_data['created'] = post.created.strftime('%B %d, %Y %I:
%M %p')
response_data['author'] = post.author.username
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({"nothing to see": "this isn't happening"}),
content_type="application/json"
)

Here we grab the post text along with the author and update the database. Then we create a
response dict, serialize it into JSON, and then send it as the response which gets logged to the
console in the success handler: console.log(json), as you saw in the create_post()
function in the JavaScript file above.
Test this again.
You should see the object in the console:

https://realpython.com/blog/python/django-and-ajax-form-submissions/

6/11

10/2/2014

1
2
3
4

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

form submitted!
create post is working!
Object {text: "hey!", author: "michael", postpk: 15, result: "Create pos
t successful!", created: "August 22, 2014 10:55 PM"}
success

How about we add the JSON to the DOM


(http://en.wikipedia.org/wiki/Document_Object_Model)!

Updating the DOM


Update the template
Simply add an id of talk to the <ul>:
1

<ul id="talk">

Then update the form so that errors will be added:


1
2
3
4
5
6
7
8

<form method="POST" id="post-form">


{% csrf_token %}
<div class="fieldWrapper" id="the_post">
{{ form.text }}
</div>
<div id="results"></div> <!-- errors go here -->
<input type="submit" value="Post" class="tiny button">
</form>

Update main.js
Now we can add the JSON to the DOM where that new talk id is:
1
2
3
4
5
6

success : function(json) {
$('#post-text').val(''); // remove the value from the input
console.log(json); // log the returned json to the console
$("#talk").prepend("<li><strong>"+json.text+"</strong> - <em> "+json
.author+"</em> - <span> "+json.created+"</span></li>");
console.log("success"); // another sanity check
},

Ready to see this in action? Test it out!

https://realpython.com/blog/python/django-and-ajax-form-submissions/

7/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

If youd like to see what an error looks like, then comment out all the CSRF Javascript in main.js
and then try to submit the form.

Rinse, Repeat
Your turn. We need to handle some more events. With your new found knowledge of jQuery and
AJAX, you get to put these into place. I added code to the final app which you can download
here (https://github.com/realpython/django-form-fun/tree/master/part1) that includes a delete
link. You just need to add an event to handle the click, which then calls a function that uses AJAX
to send a POST request to the back-end to delete the post from the database. Follow the same
workflow as I did in this tutorial. Well post the answer to this next time.
If you get stuck, and cant debug the errors, follow this workflow
1. Use the Google-it-first algorithm
2. Struggle. Spin your wheels. Set the code aside. Run around the block. Then come back to it.
3. Still stuck? Comment below, stating first the problem and then detailing the steps youve
taken to solve the problem thus far
Be sure to try troubleshooting on your own before asking for help. Spinning your wheels,
hacking away at a solution will benefit you in the long run. Its the process that matters, not so
much the solution. Its part of what separates poor developers from great developers. Good luck.
Check out the solution here (https://realpython.com/blog/python/django-and-ajax-formsubmissions-more-practice/).

https://realpython.com/blog/python/django-and-ajax-form-submissions/

8/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

Conclusion
How does your app look? Ready for more?
1. AJAX is so yesterday. We can do a lot more with much less code using AngularJS.
2. In most cases, its a standard to couple the client-side JavaScript, whether its AJAX or
Angular or some other framework, with a server-side RESTful API.
3. Wheres the tests?
What would you like to see next? Comment below. Cheers!
Happy coding!
Link to repo (https://github.com/realpython/django-form-fun).
Posted by Real Python Aug 25th, 2014 django (/blog/categories/django/), front-end
(/blog/categories/front-end/), python (/blog/categories/python/)
Tweet

17

15

Want to learn more? Download the Real Python course.


Download Now $60 (https://app.simplegoods.co/i/IQCZADOY)
Or, click here (http://www.realpython.com/) to learn more about the course.

Flask by Example - Text Processing with Requests, BeautifulSoup, and NLTK (/blog/python/flask-by-example-part-3text-processing-with-requests-beautifulsoup-nltk/)
Django and AJAX Form Submissions - more practice (/blog/python/django-and-ajax-form-submissions-morepractice/)

Comments
4 Comments

Real Python

Login

Share Favorite

Sort by Best

Join the discussion


Joseph Brown

a month ago

https://realpython.com/blog/python/django-and-ajax-form-submissions/

9/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

Jatinder's method, less code, same result.


The only problem I have with ajax, is you're kinda going behind the back of the browser.
For the most part, that's okay. But! on shakey Internet connections, it tends to leave both
the browser and users in the dark about the transaction. Cue's to the user are generally a
good idea, but more code...
cable/wifi/wireless connections have a funny way of behing shakey...

Reply Share

michaelherman

Mod

> Joseph Brown a month ago

Jatinder's method is not the same. Plus, less code does not always lead to the
ideal solution. I tend to be a little more explicit in my code for readability (mostly for
other developers and my future self)
Some form of asynchronous JavaScript has become the norm, whether it's AJAX
or a front end framework. But yes - cues/alerts/etc. to the end user are necessary,
regardless of whether you're using the Django mechanics or AJAX or Angular or
React...

Reply Share

Jatinder Pal Singh

a month ago

HI, can't we just add csrf_token in data part of ajax call? like
data: {
'csrfmiddlewaretoken': '{{csrf_token}}'
}
I have been using this and it works fine. But I wanted to know if this is the safe way of
doing it? I have seen instances where I can actually see csrftoken value in firebug. Is this
normal? And is this safe?
thanks in advance

Reply Share

michaelherman

Mod

> Jatinder Pal Singh a month ago

Yes - you can manually pass it in with the POST request. Just don't forget to do it.
The method I used does it automatically by updating the headers.
https://docs.djangoproject.com...

Reply Share

WHAT'S THIS?

ALSO ON REAL PYTHON

Flask by Example - Part 3 - Text


Processing with requests BeautifulSoup
https://realpython.com/blog/python/django-and-ajax-form-submissions/

Django Migrations - A Primer


6 comments 2 months ago

10/11

10/2/2014

Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python

Processing with requests BeautifulSoup


NLTK
7
comments 2 months ago

6 comments 2 months ago

Nanda P Very good tutorial. Good

explanation about deep migrations.I have


two apps with two models each and
populated a

Wenming Huang Good job, thanks for

your share.

Flask by Example - Part 2 - Postgres,


SQLAlchemy, and Alembic

Python Web Applications With Flask Part III

8 comments 3 months ago

5 comments 8 months ago

michaelherman I'm not sure what you're

DMJ Yea, this is a great series. Are you

asking? Are you asking why you would not


want to include everything in one script?

still planning on continuing the remaining


steps?

Categories
bottle.py (/blog/categories/bottle.py/) [ 2 ]
sql (/blog/categories/sql/) [ 1 ]
web2py (/blog/categories/web2py/) [ 1 ]
testing (/blog/categories/testing/) [ 7 ]
django (/blog/categories/django/) [ 18 ]
flask (/blog/categories/flask/) [ 15 ]
pyvows (/blog/categories/pyvows/) [ 3 ]
front-end (/blog/categories/front-end/) [ 5 ]
fundamentals (/blog/categories/fundamentals/) [ 4 ]
opencv (/blog/categories/opencv/) [ 2 ]
migrations (/blog/categories/migrations/) [ 3 ]
Copyright 2014 Real Python (https://realpython.com).
Questions? info@realpython.com (mailto:info@realpython.com).
Back to top

https://realpython.com/blog/python/django-and-ajax-form-submissions/

11/11

You might also like