Django and AJAX Form Submissions - Say 'Goodbye' To The Page Refresh - Real Python
Django and AJAX Form Submissions - Say 'Goodbye' To The Page Refresh - Real Python
Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python
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).
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
Use Protection
Regardless of whether youre using AJAX or not, forms are at risk for Cross Site Request Forgeries
(CSRF) attacks.
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.
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
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
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
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.
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
<ul id="talk">
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
},
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
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
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
Reply Share
michaelherman
Mod
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
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
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?
10/11
10/2/2014
Django and AJAX Form Submissions - say 'goodbye' to the page refresh - Real Python
your share.
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