CodeSchool DiggingIntoDjango PDF
CodeSchool DiggingIntoDjango PDF
In Try Django, we
created the
TreasureGram site,
which displays a list of
the treasures we’ve
collected along our
expeditions.
Building New Features for TreasureGram
We’d like to add the
following new features to
our TreasureGram app:
1. Grid Layout
2. Detail Page
3. Form for Adding Treasures
4. Image Uploads
5. User Authentication
6. User Profile Pages
7. Like Button With A JAX
Level 1
Each treasure is in
its own column
<div class="col-md-4">
Treasure
</div>
index.html
...
<main class="container" role="main"> Code for displaying
{% for treasure in treasures %} each treasure
<div class="treasure panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">{{ treasure.name }}</h2>
</div>
We want to put each
<div class="treasure-photo">
<img src="{{ treasure.img_url }}" height="100"> of these treasures in
</div> a row and column
</div>
</div>" and start a new row
index.html
... Start with a row
For animation, would be nice to
<main class="container container--mw700"> magic move that "<div
class="treasure panel panel-
<div class="row"> default">" line into place
{% if forloop.counter|divisibleby: 3 %}
</div><div class="row">
{% endif %}
Final Code for Creating a Grid in index.html
Putting this if statement inside our template will end the last row and create a new row
every three treasures.
index.html
...
<main class="container container--mw700">
<div class="row">
{% for treasure in treasures %}
<div class="col-md-4">
... Displaying the Treasure ... Every three columns, this line of
</div>
{% if forloop.counter|divisibleby: 3 %} code will end the last row and
</div><div class="row"> create a new one.
{% endif %}
{% endfor %}
</div>
</main>
...
Demo of Grid Working
Django Templates — Other for Loop Variables
The for loop has a number of variables available within the loop:
value | add: 2 | divisibleby: 3 Combining these filters would add 2 then check
if divisible by 3, returning True or False
click
The index page will stay simple, The detail page will show more
with just the names and images. details, like the value and location.
Creating a Detail Page
The URL will have the localhost:8000/id/
The detail page: id of the treasure.
urls.py
For our new detail page,
detail() we’ll need to create
these components.
views.py
detail.html
templates/
Adding a URL for the Detail Page
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name = 'index'),
url(r'^([0-9]+)/$',
views.detail, name = 'detail'),
]
urls.py treasuregram/views.py
...
from django.shortcuts import render
urlpatterns = [
from .models import Location
...
url(r'^/([0-9]+)/$',
def index(request):
views.detail,
...
name = 'detail'),
]
def detail(request, treasure_id):
Using the Captured id to Find a Treasure
We can find the treasure with treasure_id so that we can pass it to the template so it can
render that treasure.
treasuregram/views.py
from django.shortcuts import render
from .models import Location
def index(request):
...
treasuregram/views.py
from django.shortcuts import render
from .models import Location Should import the treasure
model
def index(request):
...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>{{ treasure.name }}</h1>
<img src="{{ treasure.img_url }}">
<p>{{ treasure.value }}</p>
<p>{{ treasure.location }}</p>
</body>
</html>
templates/index.html
<main class="container container--mw700">
<div class="row">
{% for treasure in treasures %}
<div class="col-md-4">
<a href="/{{treasure.id}}/"> Since the link tag
<div class="treasure panel panel-default"> surrounds the panel, the
... Displaying the Treasure ...
</div> whole panel will go to the
</a> detail page.
</div>
...
{% endfor %}
</div>
</main>
Demo of Detail Page Working
Now our detail
page is working!
Level 1
templates/index.html
{% load staticfiles %}
And we get our final
… Repeated code for Navbar …
combined index.html
{% block content %}
… index's code …
template!
{% endblock %}
… Repeated code for Footer …
Template Inheritance
Since all of the CSS and navbar code at the top of the file and the footer at the bottom is
repeated, we’re going to pull that out into this separate file.
treasuregram/templates/base.html
{% load staticfiles %}
<!DOCTYPE html>
<head>
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'style.css' %}" rel="stylesheet">
Shared code <title>TreasureGram</title>
</head>
<body>
<nav class="navbar navbar-default navbar-static-top text-center">
<a href="/"><img src="{% static "images/logo.png" %}"></a>
</nav>
<main class="container container--mw700">
{% block content %} This is where we will put the
{% endblock %}
page-specific code for pages
</main>
Shared code that inherit from base.html.
... footer … </body></html>
index.html Inherits From base.html
We’ll use the extends tag in index.html to inherit from base.html.
treasuregram/templates/index.html
{% extends 'base.html' %} We need to extend from
{% load staticfiles %}
base.html, and we still
{% block content %} need to load staticfiles.
<div class="row">
{% for treasure in treasures %}
... Displaying Each Treasure Panel ...
<!-- if last column in row --> We put the code specific to
{% if forloop.counter|divisibleby:"3"%} this page inside the block
</div><br><div class="row"> tags.
{% endif %}
{% endfor %}
</div>
{% endblock %}
detail.html Inherits From base.html
We’ll also use the extends tag in detail.html to inherit from base.html.
treasuregram/templates/detail.html
{% extends 'base.html' %} We need to extend from
{% load staticfiles %} base.html, and we still
Forms
Section 1
Digging Up Forms
No Way for Users to Input New Treasures
In Try Django, we were adding treasures directly to our model through the admin or the
Django shell.
L User Admin
Re
M
qu
T
H
es
s
ts
ew Edits the model directly
i
a
V
U
to add a treasure
RL
Template View Model
Gives data to
be rendered Look up or
update
Users Can Input New Treasures With a Form
Now we'd like to add a form for Users to submit new treasures to our model.
Ad ou
ds gh a
th
r
L User Admin
a
Re
TM
tr fo
qu
ea rm
H es
su
a
s ts
w Devs can edit models
re
i e
V U
R directly when needed
L
main_app/forms.py main_app/models.py
main_app/forms.py
from django import forms
class TreasureForm(forms.Form):
name = forms.CharField( label='Name', max_length=100)
value = forms.DecimalField(label='Value', max_digits=10,
decimal_places=2)
location = forms.CharField(label='Location', max_length=100)
img_url = forms.CharField(label='Image URL', max_length=255)
main_app/urls.py
urlpatterns = [
url(r'^$', views.index, name = 'index'),
url(r'^([0-9]+)/$', views.detail, name = 'detail'),
url(r'^post_url/$', views.post_treasure, name='post_treasure'),
]
The regex that will match Our view that will handle
localhost/post_url the posted data
GET vs. POST
The default request type is GET, used to get data from the server and send it back to the
client. Whenever you’re changing data on the server, you should use a POST request.
GET Treasure ?
with treasure_id
Returns Treasure
POST new
Treasure called + Treasure
'Gold Monkey'
Importing the Form in views.py
Since our form class is in a separate file, we need to import it before we can access it in a
view.
main_app/views.py
...
Create the post_treasure() View to Process Our Form
To process the submitted form, we create an instance of the form from the request and
then retrieve the form data.
main_app/views.py
...
from .forms import TreasureForm Create the form and link
... it to the posted data.
def post_treasure(request):
form = TreasureForm(request.POST)
if form.is_valid():
treasure = Treasure(name = form.cleaned_data['name'],
value = form.cleaned_data['value'],
material = form.cleaned_data['material'],
location = form.cleaned_data['location'],
img_url = form.cleaned_data['img_url'])
The form class will run validation The form class also cleans the data so it’s
for us, so this is just checking in a consistent format for the model, so
that it passed. we’ll use the cleaned_data attribute.
Saving the Treasure to the Database
Don’t forget to save the treasure to the database.
main_app/views.py
...
from .forms import TreasureForm
...
def post_treasure(request):
form = TreasureForm(request.POST)
if form.is_valid():
treasure = Treasure(name = form.cleaned_data['name'],
value = form.cleaned_data['value'],
material = form.cleaned_data['material'],
location = form.cleaned_data['location'],
img_url = form.cleaned_data['img_url'])
treasure.save()
return HttpResponseRedirect('/')
We’ll save our new treasure. Then we’ll redirect back to the homepage.
Update the index View to Display Our Form
We also need to display our empty form on our homepage.
main_app/views.py
...
from .forms import TreasureForm
... We need to update our
index view to create
def index(request):
treasures = Treasure.objects.all() a form and pass it to
form = TreasureForm() the template to
return render(request, 'index.html',
display.
{'treasures': treasures, 'form':form})
Automatically Create the Template Form Fields
In our template, we can just reference the form variable — and Django takes care of rendering
the form for us.
main_app/templates/index.html
main_app/templates/index.html
Notice there are even max_length and type variables to validate the data.
Demo of Our Django Form Working
forms.SelectDateWidget()
Level 2
Forms
Section 2
Smarter Forms With the Meta Class
Refactoring the Form to Inherit From ModelForm
By inheriting from forms.ModelForm instead of forms.Form, we’ll be able to automatically
work with form fields in the view and template.
main_app/forms.py
class TreasureForm(forms.ModelForm):
class Meta:
main_app/forms.py
class TreasureForm(forms.ModelForm):
class Meta:
model = Treasure
Adding a fields Property to the Meta Class
The fields property defines which model fields should have corresponding form inputs.
main_app/forms.py
class TreasureForm(forms.ModelForm):
class Meta:
model = Treasure
fields = ['name', 'value', 'location', 'material', 'img_url']
main_app/views.py
...
from .forms import TreasureForm
...
def post_treasure(request):
form = TreasureForm(request.POST) In a single step we’re reading all of
if form.is_valid():
the data from the form fields and
form.save(commit = True)
saving it to the database.
return HttpResponseRedirect('/')
Image Uploads
The Image Field
Adding User-uploaded Images
Users can now add new treasures, but they still can’t upload images from their computer.
class Treasure(models.Model):
name = models.CharField(max_length=100)
value = models.DecimalField(max_digits=10, decimal_places=2)
material = models.CharField(max_length=100)
location = models.CharField(max_length=100)
image = models.ImageField(upload_to='treasure_images',
default='media/default.png')
A location in the media directory media/ to add images to A default image in case it’s none
Collecting Pillow
Downloading Pillow-3.3.0-cp34-cp34m-macosx…10_x86_64.whl
(3.2MB)
100% |████████████████████████████████| 3.2MB 161kB/s
Installing collected packages: Pillow
Successfully installed Pillow-3.3.0
3 Propagate Model Changes to the Database
Since we’ve updated our model, we need to run some commands that will update the
database and make it look exactly like the structure on our Django models.
Treasuregram/settings.py
...
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
URL that handles the media The path that will hold user-uploaded files,
served from MEDIA_ROOT which is Treasuregram/media/
5 Add Special URL to Serve Media Files Locally
Adding this URL pattern will allow us to serve files (other than static files) in development.
main_app/urls.py
main_app/forms.py
class TreasureForm(forms.ModelForm):
class Meta:
model = Treasure
fields = ['name', 'value', 'location', 'material', 'image']
We’ll replace our old img_url with image so it loads the new
ImageField from our model.
2 Update the post_treasure View
In post_treasure we need to pass in request.FILES.
main_app/views.py
return HttpResponseRedirect('/')
formatting is not
3 Update Templates
consistent here
We’ll need to update a few things in our templates — the form’s enctype and updating
treasure.img_url to treasure.image.url.
main_app/templates/index.html
Users
Section 1
The User Model
Model Relationships
In databases, there are three different types of table relationships:
One-to-One Relationship One-to-Many Relationship Many-to-Many Relationship
We want a user to be able to have many treasures associated with their account.
So one user can have many treasures.
Treasure User
Since each unique user can have multiple treasures, we’ll mark the User
model as a ForeignKey in the Treasure model.
main_app/models.py
Our User field can’t be null, so we need to set a user when we add a treasure in our view.
Adding a User in the post_treasure() View
We don’t want to add a user to our form, but we do want to add a user to the treasure.
main_app/views.py
…imports…
No User
def post_treasure(request): in our
form = TreasureForm(request.POST)
if form.is_valid(): form
treasure = form.save(commit = False)
treasure.user=request.user
treasure.save()
return HttpResponseRedirect('/')
Behind the scenes in our view, we can save the treasure without
committing it and then assign the user, and then finally save the treasure.
Let’s Display an Individual User’s Treasures
To do this, we’ll want to create a profile page for each individual user. As we’ve seen before,
the steps to create a new page are creating a new:
2) View The View will look up all of the Treasures belonging to user_name
Animation - these
comments on the right
come after the stuff on the
left
1 Create a New URL for the User Profile Page
We want localhost/user/user_name to go to user_name’s profile.
main_app/urls.py
...
2 Create the View for the User Profile Page
Creating the new profile() view will take in the username so we can find that user.
main_app/views.py
main_app/views.py
...
def profile(request, username):
user = User.objects.get(username=username)
treasures = Treasure.objects.filter(user=user)
...
main_app/views.py
...
def profile(request, username):
user = User.objects.get(username=username)
treasures = Treasure.objects.filter(user=user)
return render(request, 'profile.html',
{'username': username,
'treasures': treasures})
...
We’ll pass the username and our treasures list in a dictionary to our
template profile.html for rendering.
3 Create New Profile Template
This code is very similar to index.html, but without the form.
main_app/templates/profile.html
{% extends 'base.html' %}
{% load staticfiles %}
The username we passed in
{% block content %}
<h1>{{ username }}</h1><br> The treasures list we passed in
<div class="row">
{% for treasure in treasures %} The leading slash means hostname slash, not current
<div class="col-md-4"> URL slash, so this will match localhost/id.
<div class="treasure panel panel-default">
<a href="/{{treasure.id}}/">
<div class="panel-heading">
<h3 class="panel-title">{{ treasure.name }}</h3>
</div>
</a>
Demo New Profile Page
main_app/templates/index.html
We’ll add the text by: username
...
that links to the user profile and have
<div class="treasure panel panel-default">
<div class="panel-heading"> the image link to the detail page.
<h3 class="panel-title">{{ treasure.name }}</h3>
<a class="panel-username"
href="/user/{{treasure.user.username}}/">
by: {{ treasure.user.username }}
</a>
</div>
<div class="panel-body">
<a href="/{{treasure.id}}/">
<div class="treasure-photo">
<img src="{{ treasure.image.url }}">
</div>
</a>
</div> </div> ...
Demo New Homepage and Profile Page
Level 4
Users
Section 2
User Authentication
Demo of Logging In and Logging Out
The Plan for Adding User Authentication
We want to have login and logout functionality, but will start with logging in.
We’ll follow the same steps we always have for creating a page, but add
one more step where we create a new LoginForm.
main_app/urls.py
urlpatterns = [
url(r'^user/(\w+)/$', views.profile, name='profile'),
We can’t name our
url(r'^([0-9]+)/$', views.detail, name='detail'),
url(r'^$', views.index, name='index'), view 'login' because
url(r'^post_url$', views.post_treasure), there’s a built-in
url(r'^login/$', views.login_view, name='login'),
login function we’ll
]
... be using later.
Creating the LoginForm
LoginForm is the form that will be displayed and processed by the login_view.
main_app/forms.py
class TreasureForm(forms.ModelForm):
...
class LoginForm(forms.Form):
username = forms.CharField(label='User Name', max_length=64) We can use a
password = forms.CharField(widget=forms.PasswordInput())
Password Input
widget so the
characters are
hidden.
2 Create the login_view
main_app/views.py We need to import the
LoginForm we created.
from .forms import TreasureForm, LoginForm
from django.contrib.auth import authenticate, login, logout
... To log in, we need to
def login_view(request): import authenticate
... and login functions from
django.contrib.auth
— and while we’re at it,
also logout.
2 Check the Request Type in login_view
main_app/views.py
else:
form = LoginForm()
return render(request, 'login.html',
{'form': form})
2 Log In the User in login_view
main_app/views.py
main_app/templates/login.html
{% endblock %}
Demo of the Login Form
We can now use our login form on our /login page.
Level 4
Users
Section 3
Logging Out
1 Add the Logout URL to urls.py
We’ll also want to create functionality for logging a user out. To do this, we’ll just need a URL
and a view, but not a form or template.
main_app/urls.py
urlpatterns = [
url(r'^user/(\w+)/$', views.profile, name='profile'),
url(r'^([0-9]+)/$', views.detail, name='detail'),
url(r'^$', views.index, name='index'), We’ll go ahead and
url(r'^post_url$', views.post_treasure),
add the new URL
url(r'^login/$', views.login_view, name='login'),
url(r'^logout/$', views.logout_view, name='logout'), for logging out.
]
...
2 Create the logout_view
The logout process is much simpler than logging in
main_app/views.py
...
We’ll simply call the logout
def logout_view(request): function we imported from
logout(request)
django.contrib.auth.
return HttpResponseRedirect('/')
But right now we don’t have any links set up, so a user wouldn’t know how to log in or log
out, so let’s set those up.
base.html Before Adding Login and Logout Pages
All of our pages inherit from base.html, so we want to update the navbar in base.html to have
links to log in and log out.
main_app/templates/base.html
{% load staticfiles %}
<!DOCTYPE html>
<head>...</head>
<body>
<nav class="navbar navbar-default navbar-static-top text-center">
<a href="/"><img src="{% static "images/logo.png" %}"></a>
</nav>
...
{% else %}
We’ll use a URL tag, the name of the URL, and any parameters.
{% endif %}
</nav> So if the username is Sarah, the URL will look like:
...
Adding a Link to the Login and Logout Pages
We’ll use the same URL template tag for the logout and login links.
main_app/templates/base.html
{% load staticfiles %}
<!DOCTYPE html>
<head>...</head>
<body>
<nav class="navbar navbar-default navbar-static-top text-center">
<a href="/"><img src="{% static "images/logo.png" %}"></a>
{% if user.is_authenticated %}
<a href="{% url 'profile' user.username %}">{{ user.username }}</a
<a href="{% url 'logout' %}">logout</a>
{% else %}
<a href="{% url 'login' %}">login</a>
{% endif %}
</nav>
...
Styling the Login and Logout Pages
Finally, we’ll add some style to our links with the classes navbar-text and navbar-right.
main_app/templates/base.html
...
<nav class="navbar navbar-default navbar-static-top text-center">
<a href="/"><img src="{% static "images/logo.png" %}"></a>
{% if user.is_authenticated %}
<a class="navbar-text navbar-right"
href="{% url 'profile' user.username %}">{{ user.username }}</a
<a class="navbar-text navbar-right"
href="{% url 'logout' %}">logout</a>
{% else %}
<a class="navbar-text navbar-right"
href="{% url 'login' %}">login</a>
{% endif %}
</nav>
...
Demo of Login/Logout Process
Level 5
A JAX
Section 1
Creating a Like Button
Adding a Like Button
We want to add a like button that keeps track of likes whether you’re on the homepage or on
the detail page.
We also want to use AJAX here so that the page will display
the new number of likes immediately without a page refresh.
The Plan for Creating a Like Button
As we’ve seen before, the steps to create a new page are creating a new:
๏ View The View will calculate the total likes, save to the database, and
send that value to our AJAX method to update the page.
BUT we need to do two extra steps for the like button with A JAX:
๏ A JAX After we’ve set up these basic parts, we’ll add AJAX to process our request.
๏ Model Add a like field to the Treasure model so it can save a treasure’s likes.
Adding a likes Field to Our Treasure Model
Since we want the likes to persist, we will want to keep track of likes in our database.
main_app/models.py
...
class Treasure(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
value = models.DecimalField(max_digits=10,
decimal_places=2)
location = models.CharField(max_length=100)
image = models.ImageField(upload_to='treasure_images',
default='media/default.png')
likes = models.IntegerField(default=0)
Our new IntegerField,
def __str__(self):
return self.name the default 0 will
populate existing treasures
Migrating Our Model Changes to the Database
We'll create our migrations.
{% block content %}
<div class="treasure panel panel-default">
<div class="panel-heading">...</div>
<div class="panel-body">
… Displaying the Treasure … revisit the HTML here
Now that we’ve set up the model and the template, let’s look at adding the AJAX process!
Before Adding A JAX, Revisiting a Django Request
Here’s a Django web request flow in more detail.
Look up all
treasures
models in the database
Adding a Like Button With A JAX
HTML
A Django Web
Request
urls views templates
index() index.html
Click
Update with
new # of likes
tr Sa
ea
su ve JS
G re
et .li urls
A Web Request tr ke JavaScript intercepts
e
by as s
With AJAX GET treasure_id the click event
id ure
views with A JAX
# of likes
like_treasure()
Downloading and Including jQuery
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>...</head>
<body>
<nav>...</nav>
<main>...</main>
<footer ... >...</footer>
<script src="{% static 'js/jquery-3.0.0.min.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
We can add our script tags to the bottom of base.html, and then they’ll be
available to anything that inherits from base.html.
Adding a Click Event Listener to main.js
This function will run whenever a button is clicked on an HTML page.
main_app/static/js/main.js
...
$('button').on('click', function(event){
event.preventDefault();
var element = $(this);
Looking for a button click event
});
Making an A JAX Request
main_app/static/js/main.js
...
$('button').on('click', function(event){
event.preventDefault();
var element = $(this);
$.ajax({ This URL will be called
url : '/like_treasure/', when a button is clicked.
type : 'GET',
data : ???,
});
}); The value for data should be whatever
information we want to pass to the view.
Sending Data About Which Like Button Was Tapped
main_app/static/js/main.js
...
$('button').on('click', function(event){
event.preventDefault();
var element = $(this);
$.ajax({
url : '/like_treasure/',
type : 'GET',
data : { treasure_id : element.attr("data-id")},
urlpatterns = [
...
url(r'^like_treasure/$', views.like_treasure, name='like_treasure' ),
...
]
Adding Our like_treasure() View
The like_treasure() view will find the treasure with id treasure_id passed from the A JAX GET
and update its likes.
main_app/views.py
...
def like_treasure(request):
treasure_id = request.GET.get('treasure_id', None) Use the submitted id
to get the treasure
likes = 0
object from the
if (treasure_id):
treasure = Treasure.objects.get(id=int(treasure_id)) database.
if treasure is not None:
likes = treasure.likes + 1
treasure.likes = likes If the object exists, increase
treasure.save()
likes by 1 and save that
return HttpResponse(likes) back to the database.
});
}); On success, we want the button to display the updated
number of likes that is returned by the view.
Updating the HTML Button with # of likes
HTML
A Django Web
Request
urls views templates
index() index.html
Click
Update with
new # of
tr sa likes
ea
su ve
re JS
G .li
A Web Request et ke urls
tr s Now the AJAX
With AJAX by eas GET treasure_id
id ure updates the page.
views With A JAX
like_treasure() # of likes
Demo of Our Treasure Likes in Action
This is what some text content will look like.
Level 5
A JAX
Section 2
Using POST Requests With A JAX
Using a POST Request Instead of GET
As we said before in Level 2, a GET is used to retrieve data from the database, whereas a
POST will change the state of the system.
HTML
Since we’re updating a treasure’s
likes, a POST would be better.
Click
Update with
new # of likes
tr sa
ea
su ve JS
G re.
et l urls
tr ik JavaScript intercepts
e es
by as POST treasure_id
id ure the click event
views With A JAX
like_treasure() # of likes
Updating the A JAX Request Type to a POST
main_app/static/js/main.js
...
$('button').on('click', function(event){
event.preventDefault();
var element = $(this);
$.ajax({
url : '/like_treasure/', We just need to
type : 'POST',
change the type
data : { treasure_id : element.attr("data-id")},
from GET to POST.
success : function(response){
element.html(' ' + response);
}
});
});
Updating like_treasure() View
The like_treasure() view will now get the treasure_id passed from the A JAX POST.
main_app/views.py
...
def like_treasure(request):
treasure_id = request.POST.get('treasure_id', None) Change
likes = 0 request.GET to
if (treasure_id): request.POST
treasure = Treasure.objects.get(id=int(treasure_id))
if treasure:
likes = treasure.likes + 1
treasure.likes += likes
treasure.save()
return HttpResponse(likes)
If We Run This Code, We Get a Problem
$ python manage.py runserver
Performing system checks...
We get this error because in Django, a POST needs a CSRF token to prevent a CSRF attack.
Since we’re doing the POST through AJAX, we can’t just put it in the form like we did before.
A JAX Code for Passing CSRF Tokens
There is A JAX code provided on Django’s docs that will transfer the CSRF token to our A JAX
POST request for us from the user’s session cookie.
For AJAX, we can look up CSRF token in the user’s session cookie, then add it to the POST header.
CSRF token
POST with CSRF
click A JAX cookie token in header Django
We won’t go into this code in detail, but we’ll add it to our main.js script.
Find out more about Django, CSRF, and AJAX here: go.codeschool.com/django-csrf-ajax
A JAX Code for Passing CSRF Tokens
main_app/static/js/main.js
...
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(
cookie.substring(name.length + 1));
break;
}
} This code grabs the CSRF token
}
return cookieValue; from the user’s session cookie.
}
var csrftoken = getCookie('csrftoken');
A JAX Code for Passing CSRF Tokens
This is what some text content will look like. Its your body copy.
main_app/static/js/main.js
...
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
This code sets the CSRF token inside request header
});
for any unsafe (POSTs) or non-cross-domain requests.
Demo of Our Treasure Likes in Action
This is what some text content will look like.