Vous êtes sur la page 1sur 147

What Do You Need to Know to Take This Course?

This course builds upon the


concepts taught in Try Django.

Try Django incorporates concepts taught in these prerequisite courses:

Basic Python Basic HTML & CSS Basic Database Concepts


Where Try Django Left Off

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

Templates & Inheritance


Section 1
Delving Into Grids
How to Create a Grid With Rows and Columns
Using Bootstrap, we can create a grid with a new row every three columns.

Each treasure is in
its own column
<div class="col-md-4">
Treasure
</div>

Start a new row 



every three treasures
<div class="row">
<div class="col-md-4">
Treasure
</div>
… 2 more Treasure cols
</div>
Our index.html Template Now
index.html
...
<main class="container" role="main">
{% for treasure in treasures %}
<div class="treasure panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">{{ treasure.name }}</h2>
</div>
<div class="panel-body"> We can remove the table code for
<table class="treasure-table"> the value, material, and location
<tr>
<th> since that will be on the detail page.
<img src="{% static 'images/materials-icon.png' %}" >
Material:
</th>
<td>{{treasure.material}}</td>
</tr>
<tr>
...
</div></div>'</main>...
Our index.html Template Now
Our current homepage has a for loop that puts each treasure in a panel.

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

{% endfor %} every three treasures.


</div>'
</main>...
Each Treasure in Its Own Column
We’ll create a row outside of the for loop and a column for each treasure.

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

{% for treasure in treasures %} Each treasure is in


<div class="col-md-4"> its own column
<div class="treasure panel panel-default">
...
</div>"
</div>
{% endfor %}
</div>'
</main>
...

Let’s see how our grid is looking so far…


Our Grid Doesn’t Seem to Be Working

Since some of our images


have different heights, we
have a problem…

To fix this, we can create a


new row every three treasures.

But how do we get the for


loop counter and check if
it’s divisible by 3?
Template for Loop Variables and Filters
The for loop has a number of variables available within the loop:

We can use this to see how many


forloop.counter The number of iterations so far
treasures are displayed so far.

In addition to template tags, Django provides filters to help process data:

We can use this to check if our


value | divisibleby: 3 Returns True or False treasure count is divisible by 3.

So the code to create new rows in our template becomes:

{% 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:

forloop.counter 1 based for loop count

forloop.counter0 0 based for loop count

forloop.first Is this the first iteration?


True or False
forloop.last Is this the last iteration?
Django Templates — Other Filters
In addition to template tags, Django provides filters to help process data.

value | add: 2 Returns value + 2

name | lower Returns name in lowercase

value | add: 2 | divisibleby: 3 Combining these filters would add 2 then check
if divisible by 3, returning True or False

There are many more Django template filters, which you


can find in the docs here:
go.codeschool.com/django-template-tags
Level 1

Templates & Inheritance


Section 2
Delving into Details
Creating a Detail Page
The index page: The detail page:

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'),
]

This URL looks for a number and captures


that value to send to the detail view.
Writing Regex to Match a Detail URL
Currently we have the following empty path go to the homepage:

This index URL would match


r'^$' localhost

We want a URL that will match a treasure’s id:

This detail URL would match


r'^([0-9]+)/$' localhost/0 Then this value is automatically
passed into the detail() view.
localhost/5
[0-9]+ will match any number,
the ( ) capture the value localhost/15
Matches any URL
with a number

Note: If you want to learn more regex, check out our


Breaking the Ice With Regular Expressions course!
Accessing the Value Captured in the URL
The treasure_id is automatically passed from the URL dispatcher to an argument in the detail view.

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):
...

def detail(request, treasure_id):


treasure = Treasure.objects.get(id=treasure_id)

You may be wondering where the id came from?


It’s auto-generated in our model, which we’ll see in a second.
Our Current Treasure Model
models.py

from django.db import models

# Create your models here.


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)
img_url = models.CharField(max_length=100)
...

Notice that we didn’t define an id.


So how did we look up a treasure by its id?
Treasure Object’s Primary Key
By default, Django gives each model an auto-incrementing primary key field:

id = models.AutoField(primary_key=True) Each model requires exactly one field


This code happens behind the scenes in your model. to have primary_key=True
(either explicitly declared or
automatically added).

We can look up this primary key with id:


In the detail view, we can look up the
treasure = Treasure.objects.get(id='1')
treasure with a specific id.
Passing the Retrieved Object to the Detail Template
We can then pass the treasure object to our detail.html template.

treasuregram/views.py
from django.shortcuts import render
from .models import Location Should import the treasure
model

def index(request):
...

def detail(request, treasure_id):


treasure = Treasure.objects.get(id=treasure_id)
return render(request, 'detail.html', {'treasure': treasure})

In Try Django, we learned about


passing data into a template.
Adding the Detail Template
templates/detail.html

<!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>

We can pull in the treasure’s fields to see that


our detail page is working before adding style.
Adding Style to the Detail Template
treasuregram/templates/detail.html

... <main ...> treasure is passed


<div class="treasure panel panel-default"> in from the view. The detail template
<div class="panel-heading"> will look identical to
<h3 class="panel-title">{{ treasure.name }}</h3>
</div> our old homepage,
<div class="panel-body"> except we don’t
<div class="treasure-photo-detail"> need a for loop.
<img src="{{ treasure.image.url }}" height="200">
</div>
<table class="treasure-table">
<tr>
<th>
<img src="{% static "images/material.png" %}">
Material:
</th>
<td>{{ treasure.material }}</td>
</tr>
</table>
</div> </div> </main> ...
How Do We Link to Our Detail Page?
The index page: The detail page: The URL will have the
id of the treasure.

We need each treasure to link to


localhost/treasure.id
Link From index.html
We need an HTML link tag <a></a> so when a treasure is clicked. it goes the detail page

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 & Inheritance


Section 3
Inspecting Template Inheritance
Repeated Code in Templates
Each page on our site will have repeated code for at least the header, navbar, and footer.

How can we share this repeated


code across templates?
Template Inheritance
We’ll create base.html to hold the repeated code for the navbar and footer, which index.html
and eventually detail.html will use.

templates/base.html New file


{% load staticfiles %}


… Repeated code for Navbar …



 When rendering, any code
{% block content %}
 inside of index.html's
{% endblock %} Placeholder for where

the child code in {block content}
… Repeated code for Footer … … {endblock}
index.html will go tags is loaded into
templates/index.html base.html's block
content tags
{% extends 'base.html' %} Need to specify if inheriting
{% load staticfiles %}
{% block content %}
The code specific to
… index's code …

{% endblock %} index.html, like our
Grid of Treasures
The Resulting index.html File
The result of combining base.html with index.html into one complete template.

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

{% block content %} need to load staticfiles.


<div class="treasure panel panel-default">
<div class="panel-heading"> We put the code
<h3 class="panel-title">{{ treasure.name }}</h3>
</div> specific to this page
<div class="panel-body"> inside the block tags.
<div class="treasure-photo-detail">
<img src="{{ treasure.image.url }}">
</div>
<table class="treasure-table"> ... </table>
</div>
</div>
{% endblock %}
Demo of Detail Page Working
Now our detail
page is working!
Level 2

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

Template View Model


Gives data to
be rendered Look up or
update
Fields From Form Class Map to HTML Elements
To use a Django form, we need to define a new class that inherits from forms.Form.

main_app/forms.py main_app/models.py

from django import forms from django.db import models

class TreasureForm(forms.Form): class Treasure(models.Model):


name = forms.CharField(…) name = models.CharField(…)
value = forms.DecimalField(…) value = models.DecimalField(…)
material = forms.CharField(…) material = models.CharField(…)
location = forms.CharField(… ) location = models.CharField(…)
img_url = forms.CharField(…) img_url = models.CharField(…)

Our form class is going to look Our model we previously created


almost identical to our model’s.

In a similar way that a model class’s fields map to database fields,


a form class’s fields map to HTML form <input> elements.
Django Form Fields Are Similar to Model Fields
Django takes some of the work out of creating form fields and validating form data.

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)

Notice the fields are almost identical to the model fields,


but we can also define the label.
Adding the URL to Post Our Form Submission

main_app/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'),
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

from django.shortcuts import render


from django.http import HttpResponse
from .models import Treasure
from .forms import TreasureForm

...
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 ...> Required when doing a


... post request in Django
<form action="post_url/" method="post"> to protect against CSRF
{% csrf_token %}
{{ form }} (cross-site request
<input type="submit" value="Submit" /> forgery) attacks
</form>
</main>
Update the Form Style
We can add some style to our form so it fits in with the rest of the homepage.

main_app/templates/index.html

<div class="treasure panel panel-default">


Adding a few Bootstrap styles
<div class="panel-heading">
<h3 class="panel-title">Add Treasure</h3> to make the form fit in and
</div> look cleaner
<div class="panel-body">
<form action="post_url/" method="post" >
{% csrf_token %} .as_p formats like an HTML
{{form.as_p}}
<input type="submit" value="Submit" /> paragraph and displays each
</form> form input on a new line.
</div>
</div>
Viewing the HTML Source for Our Form
Notice when we view the HTML source that all of the labels and input fields are filled in for us.

The csrf middleware token also has a value.

Notice there are even max_length and type variables to validate the data.
Demo of Our Django Form Working

fix this video to have a


field for material in it

You may be wondering


if Django forms can
render anything other
than just simple text
fields…
Form Widgets
Django form widgets, defined in the forms class, can render more complex things like
password fields or date pickers, which we’ll use later in this course.

We’ll see the PasswordInput


widget later in the course:
forms.CharField(widget=
forms.PasswordInput())

There are many more widgets available, such as:


FileInput, CheckboxInput, DateInput

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.

Before the change After the change


main_app/forms.py main_app/forms.py

from django import forms from django import forms


from .models import Treasure
class TreasureForm(forms.Form):
name = forms.CharField(…) class TreasureForm(forms.ModelForm):
value = forms.DecimalField(…)
material = forms.CharField(…)
location = forms.CharField(…) This is the first step to linking
img_url = forms.CharField(…) a form with a model.
Creating a Meta Class in the Form
The Meta class allows us to define properties that help us link the form and model together.

main_app/forms.py

from django import forms


from .models import Treasure

class TreasureForm(forms.ModelForm):
class Meta:

The name of this class will


always be "Meta".
Adding a Model Property to the Meta Class
The model property is used to define which model the form will be created from, which in
our case is the Treasure model.

main_app/forms.py

from django import forms


from .models import Treasure

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

from django import forms


from .models import Treasure

class TreasureForm(forms.ModelForm):
class Meta:
model = Treasure
fields = ['name', 'value', 'location', 'material', 'img_url']

The HTML form will display labels


and inputs for these five fields.
Updating the post_treasure View to Use the New ModelForm
The form object is created the same way, but now we don’t need to manually create a
Treasure object and save the fields in separate steps.

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('/')

We still want to redirect to the index after saving.


Demo of Our Django Form Still Working
This is what some text content will look like.

fix this video to have a


field for material in it
Level 3

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.

Right now, each image needs to be


hosted on another server, but we’d
like to be able to upload images
directly into our application.
Adding User-uploaded Images
To allow users to upload images from their computer, we’ll need to use an ImageField.

Required steps to set up ImageField:


1) Add ImageField to our model
2) Install Pillow — an image-processing library necessary for ImageField
3) Migrate changes
4) Update settings.py to add a media directory
5) Add a special debugging URL to urls.py to serve our media files locally
1 Add Our Image Model to models.py
main_app/models.py

from django.db import models

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

If we try to run makemigrations or runserver, we’ll get the following error:


ERRORS:
main_app.Treasure.image: Cannot use ImageField because Pillow is not
installed. HINT: Get Pillow at https://pypi.python.org/pypi/Pillow
or run command "pip install Pillow".
2 Install Pillow to Use the ImageField
We can use pip to install Pillow (a Python image-processing library) that is necessary
to use ImageField.

> pip install Pillow

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.

> python manage.py makemigrations Generate


migration files
Migrations for 'main_app':
0006_treasure_image.py: based on our
- Add field image to treasure current Django
models.

> python manage.py migrate Update the

Operations to perform: database.


Apply all migrations: auth, main_app, sessions,
contenttypes, admin
Running migrations:
Rendering model states... DONE
Applying main_app.0006_treasure_image... OK
4 Update Settings and Create Media Directory
At the bottom of our settings.py file, we need to set up the directory MEDIA_ROOT that will hold
user-uploaded files and the MEDIA_URL, which handles serving the media in MEDIA_ROOT.

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

from django.conf.urls import url


from django.conf import settings
Need to import the
from django.views.static import serve
from . import views serve() view to
call it below
urlpatterns = [ Sends any URL that
url(r'^$', views.index), matches media/
url(r'^([0-9]+)/$', views.detail),
to a built-in Django
]
view called
# Add to the bottom of your file static.serve()
if settings.DEBUG:
urlpatterns += [
url(r'^media/(?P<path>.*)$', serve,
{'document_root': settings.MEDIA_ROOT,}),
]
Adding User-uploaded Images
We’ve set up the ImageField, but we still need to do some refactoring…

Required steps to set up ImageField:


1) Add ImageField to our model
2) Install Pillow — an image-processing library necessary for ImageField
3) Migrate Changes
4) Update settings.py to add a media directory
5) Add a special debugging url to urls.py to serve our media files locally

Things to refactor to replace our old image URL with ImageField:


1) forms.py
2) views.py
3) Templates — index.html and detail.html
1 Update Form
We’ll update our form to use the new ImageField.

main_app/forms.py

from django import forms


from .models import Treasure

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

The view needs access to our


...
uploaded files to save the image.
def post_treasure(request):
form = TreasureForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit = True)

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

<form enctype="multipart/form-data" action="post_url/" method="post" >


{% csrf_token %}
<div class="field-wrapper"> This is required when submitting files to the server.
{{form.as_p}}
</div>
<input type="submit" value="Submit" />
</form>

We’ll also replace any references to


Before: <img src="{{ treasure.img_url }}">
treasure.img_url with

After: treasure.image.url in our


<img src="{{ treasure.image.url }}">
index.html and detail.html.
Demo of ImageField Upload Working
We can see that our image
successfully uploaded to
our media directory since
we can now see our new
treasure displayed on our
page.
Level 4

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

id user name value … id username password …

1 1 Gold Nugget 1000.00 … 1 sbuchanan …

2 1 Fools Gold 15.00 … 2 indiana ….

3 2 Golden Monkey 2500.00 …

4 2 Golden Chimp 35000.00


For more concepts like these,
check out our database courses:
https://www.codeschool.com/learn/database
One-to-Many — User-to-Treasure Relationship
The way to relate two tables together is to mark a field from one table as a ForeignKey in another.

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

from django.contrib.auth.models import User Django actually creates a


... User model as part of
class Treasure(models.Model): the auth module, so
user = models.ForeignKey(User)
we’ll import that.
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=get_image_path,
default='media/default.png')
Running makemigrations
Remember: Any time we make any change to a model, we have to migrate our changes.

> python manage.py makemigrations

You are trying to add a non-nullable field 'user' to treasure without


a default; we can't do that (the database needs something to populate
existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option: 1

Please enter the default value now, as valid Python


The datetime and django.utils.timezone modules are available, so you
can do e.g. timezone.now()
>>> 1

Migrations for 'main_app':


0004_treasure_user.py:
- Add field user to treasure
Running migrate
We’ll then apply our migrations.

> python manage.py migrate


Operations to perform:
Apply all migrations: auth, contenttypes,
admin, main_app, sessions
Running migrations:
Rendering model states... DONE
Applying main_app.0004_treasure_user... OK
Creating User in the Admin
This is what some text content will look like. Its your body copy.
Editing Existing Treasures and Assigning Users
This is what some text content will look like. Its your body copy.

Now we can use the


Django admin to create
a user and assign
treasures to a user.
If We Try to Post a New Treasure, We Get an Error
After submitting a new treasure we see this error (these errors only show up in Debug mode)

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:

1) URL We want localhost/user/user_name to go to user_name’s profile

2) View The View will look up all of the Treasures belonging to user_name

3) Template And the Template will display all of those Treasures

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

from django.conf.urls import url


from django.conf import settings
from . import views We can use the regex
(\w+) which will
urlpatterns = [
url(r'^user/(\w+)/$', views.profile, name='profile'), capture a word of any
url(r'^([0-9]+)/$', views.detail), length — so it will
url(r'^$', views.index),
capture a username.
]

...
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

... We can look up the user


def profile(request, username): object in the User model
user = User.objects.get(username=username) by its username.

Next, we’ll look up all of the


...
treasures that belong to this user.
2 Filter Treasures by User
We can use a QuerySet filter to only return the treasures for this user.

main_app/views.py

...
def profile(request, username):
user = User.objects.get(username=username)
treasures = Treasure.objects.filter(user=user)
...

This QuerySet filter will look up all of


the treasures that belong to this user.
2 Render the profile.html Template
Finally, we can render the template to show this user’s treasures.

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

We can only get to this page by


typing in the URL, so we want a link
to this page from the homepage.
Updating index.html to Link to Profiles
We’ll update the title of a treasure to also display by: username and link to their profile.

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.

1) URL We want localhost/login to go to a login form.


Animated Form in last and
have other stuff slide
down
New step! Form We need to add a new step to add the forms for login.

2) View We’ll create Views that will handle login.

3) Template We’ll need a Templates for login.


1 Update urls.py With the Login View
We’ll add our new login URL to urls.py.

main_app/urls.py

from django.conf.urls import url


from django.conf import settings
from . import views

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

from django import forms

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

from .forms import TreasureForm, LoginForm


from django.contrib.auth import authenticate, login, logout
...
def login_view(request): Check whether the request
if request.method == 'POST': was a POST or not.

If this was a POST, then we would


want to authenticate the submitted
username and password.

If it’s not a POST,


simply display the
else: LoginForm.
form = LoginForm()
return render(request, 'login.html',
{'form': form})
2 Call the Authenticate Method in login_view
main_app/views.py

from .forms import TreasureForm, LoginForm


from django.contrib.auth import authenticate, login, logout
...
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
We’ll use the username
if form.is_valid():
u = form.cleaned_data['username'] and password with the
p = form.cleaned_data['password'] built-in authenticate
user = authenticate(username = u, password = p)
function — if the user
exists, it will return the
correct user.

else:
form = LoginForm()
return render(request, 'login.html',
{'form': form})
2 Log In the User in login_view
main_app/views.py

from .forms import TreasureForm, LoginForm


from django.contrib.auth import authenticate, login, logout
...
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
u = form.cleaned_data['username']
p = form.cleaned_data['password'] If we have an active
user = authenticate(username = u, password = p)
if user is not None: user, we can use the
if user.is_active: built-in login function
login(request, user) to log in.
return HttpResponseRedirect('/')
else:
Then we’ll redirect to
form = LoginForm()
return render(request, 'login.html', the homepage.
{'form': form})
Adding Messages for Users Who Can’t Log In
main_app/urls.py
...
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid(): We can also
u = form.cleaned_data['username'] provide feedback
p = form.cleaned_data['password']
if the username
user = authenticate(username = u, password = p)
if user is not None: or password are
if user.is_active: incorrect, or if
login(request, user)
the account is
return HttpResponseRedirect('/')
else: disabled.
print("The account has been disabled!")
else:
print("The username and password were incorrect.")
else:
...
3 Create the Template That login_view Displays
Finally, we’ll create the templates with the forms for logging in and registering.

main_app/templates/login.html

{% extends 'base.html' %} A dot "." means POST back to


{% load staticfiles %} this same URL, which will work
{% block content %}
since our login_view will
<h1>Login</h1> handle both a POST and a GET.
<form method="post" action=".">
{% csrf_token %} The template will use the
{{ form.as_p }}
passed-in form variable to
<input type="submit" value="Submit" />
</form> display the form.

{% 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

from django.conf.urls import url


from django.conf import settings
from . import views

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('/')

Then redirect to the


homepage.

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>
...

Add login/logout links here.


Using Conditionals to Check if the User Is Logged In
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>
{% if user.is_authenticated %} User is available through the request.
...
If the user is logged in, let’s have a link
{% else %} to their profile and a link to log out.
...
Otherwise, let’s add a link to log in.
{% endif %}
</nav>
...
Adding a Link to the User Profile
The URL template tag lets you use the name of the URL ('profile' here) defined in urls.py
instead of hardcoding a link, so if the link changes, you can just change it in urls.py.
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

{% 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:

๏ URL We want localhost/like_treasure to go to the like_treasure view.

๏ View The View will calculate the total likes, save to the database, and
send that value to our AJAX method to update the page.

๏ Template We’ll update the index.html and detail.html Templates so


they can display the button and the updated number of likes.

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.

We can do this by adding a likes field to our Treasure model.

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.

> python manage.py makemigrations

Migrations for 'main_app':


0013_treasure_likes.py:
- Add field likes to treasure

Then apply our migration to the database.

> python manage.py migrate


Operations to perform:
Apply all migrations: auth, contenttypes,
admin, main_app, sessions
Running migrations:
Rendering model states... DONE
Applying main_app.0013_treasure_likes... OK
Updating the index.html to Display a Button
main_app/templates/index.html

{% block content %}
<div class="treasure panel panel-default">
<div class="panel-heading">...</div>
<div class="panel-body">
… Displaying the Treasure … revisit the HTML here

<button id ="likes" data-id="{{treasure.id}}"


class="btn btn-mini btn-danger glyphicon glyphicon-heart"
type="button">
{% if treasure.likes > 0 %} {{ treasure.likes }} {% endif %}
</button>

</div> Also add this block to


</div>
{% endblock %} the detail.html page

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.

Any clicked links go


A Django Web through the URL dispatcher
Request
HTML

localhost:8000/ urls views templates


index() index.html
JS

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

Download the jQuery file at go.codeschool.com/download-jquery


and put it in main_app/static/js

While we’re at it, we’ll also create main.js for


writing our application-specific AJAX code.

Find out more about jQuery


in our jQuery courses!
Referencing Our JavaScript Files in base.html
main_app/templates/base.html

{% 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

We’ll then save the clicked element.

});
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")},

}); We’ll look up the value for the button’s data-id


});
attribute, which will have the treasure’s id.

Remember this main_app/templates/index.html


from the template?
<button ... data-id="{{treasure.id}}" ... >...</button>
How Do We Know Which Treasure Was Clicked?
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
A Web Request et .li urls
tr ke JavaScript intercepts
e
by as s
With AJAX id ure GET treasure_id the click event
views with A JAX
# of likes
like_treasure()

We just added this treasure id to the GET — now we can look


up the treasure with the id in the like_treasure() view.
Creating a New URL for Liking a Treasure
main_app/urls.py

... imports ...

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.

Return the updated likes


value as an AJAX response.
Returning the Number of Likes to A JAX
HTML
A Django Web
Request
urls views templates
index() index.html
Click
Update with
new # of likes
tr Sa
ea
su ve
re JS
G .li urls
A Web Request et ke
tr s JavaScript intercepts
e
by as
With AJAX id ure
GET treasure_id the click event
views with A JAX
like_treasure() # of likes

Now the like_treasure() view


returns the number of likes to the AJAX.
Updating the UI After Updating the Likes
main_app/static/js/main.js
...
$('button').on('click', function(event){
event.preventDefault(); main_app/views.py
var element = $(this); …
$.ajax({ return HttpResponse(likes)
url : '/like_treasure/',
type : 'GET',
data : { treasure_id : element.attr("data-id")},
This response contains the
success : function(response){ updated number of likes
element.html(' ' + response);
} from treasure_view().

});
}); 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...

System check identified no issues (0 silenced).


June 20, 2016 - 20:28:31
Django version 1.9.2, using settings 'Treasuregram.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[20/Jun/2016 20:28:35] "GET / HTTP/1.1" 200 9058
[20/Jun/2016 20:28:35] "GET /static/css/style.css HTTP/1.1" 304 0
[20/Jun/2016 20:28:35] "GET /static/js/jquery-3.0.0.min.js HTTP/1.1" 304 0
... Other static assets

Forbidden (CSRF token missing or incorrect.): /like_treasure/


[20/Jun/2016 20:28:39] "POST /like_treasure/ HTTP/1.1" 403 2274

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.

In Level 2, we had a form POST, with { %csrf_token %} added in the template.

CSRF token add template icon


POST with CSRF
template token in header Django

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.

Vous aimerez peut-être aussi