Bootcamp
Searchโ€ฆ
9.3.1: Django User Login
User auth in Django is mostly built-in. We'll follow through the steps needed to use this part of the library.

Setup

django-extensions

django-extensions is a popular add-on to Django that includes a variety of functionality. We will use it to gather more information about our built-in functionality on the command line, but it does a lot of different things.
1
pip3 install django-extensions
Copied!
Install django-extensions into the app:

my_ra_django_project/settings.py

1
INSTALLED_APPS = (
2
...
3
'django_extensions',
4
...
5
)
Copied!
See more on django-extensions here and here.

URLs

Initialize the built-in Django auth urls by adding them to the project.

my_ra_django_project/urls.py

1
from django.contrib import admin
2
from django.urls import include, path
3
โ€‹
4
urlpatterns = [
5
path('admin/', admin.site.urls),
6
path('', include('my_ra_django_app.urls')),
7
path('accounts/', include('django.contrib.auth.urls')),
8
]
Copied!
Use django-extensions to print out the URLs set by django.contrib.auth.urls.
1
python manage.py show_urls
Copied!
Setting the single line in urls.py creates these matching URLs in Django:
1
/accounts/login/ django.contrib.auth.views.LoginView login
2
/accounts/logout/ django.contrib.auth.views.LogoutView logout
3
/accounts/password_change/ django.contrib.auth.views.PasswordChangeView password_change
4
/accounts/password_change/done/ django.contrib.auth.views.PasswordChangeDoneView password_change_done
5
/accounts/password_reset/ django.contrib.auth.views.PasswordResetView password_reset
6
/accounts/password_reset/done/ django.contrib.auth.views.PasswordResetDoneView password_reset_done
7
/accounts/reset/<uidb64>/<token>/ django.contrib.auth.views.PasswordResetConfirmView password_reset_confirm
8
/accounts/reset/done/ django.contrib.auth.views.PasswordResetCompleteView password_reset_complete
Copied!
Visit one of the URLs here: http://localhost:8000/accounts/loginโ€‹
The error will be about a missing template file. Below we will create this and all the other missing template files.
Note that the right hand column of the output of show_urls is the url name. We'll use them in template tags below. See more about url names here: https://docs.djangoproject.com/en/3.1/topics/http/urls/#naming-url-patternsโ€‹

Sign Up

We need to create the entire signup flow. We'll use the built-in UserCreationForm model form to render the form and also to construct and save the new record.
Learn more about model forms here.โ€‹

my_ra_django_app/urls.py

1
from django.urls import path
2
โ€‹
3
from . import views
4
โ€‹
5
urlpatterns = [
6
path("owners/<int:primary_key>/", views.owners, name="owners"),
7
path('', views.index, name='index'),
8
path('signup/', views.signup, name='signup'),
9
]
Copied!

my_ra_django_app/views.py

1
from django.contrib.auth import login, authenticate
2
from django.contrib.auth.forms import UserCreationForm
3
from django.shortcuts import render, redirect
4
โ€‹
5
# ...
6
โ€‹
7
def signup(request):
8
if request.method == 'POST':
9
# request.POST contains the form data
10
form = UserCreationForm(request.POST)
11
if form.is_valid():
12
form.save()
13
username = form.cleaned_data.get('username')
14
raw_password = form.cleaned_data.get('password1')
15
user = authenticate(username=username, password=raw_password)
16
login(request, user)
17
return redirect('index')
18
else:
19
form = UserCreationForm()
20
return render(request, 'signup.html', {'form': form})
21
โ€‹
22
# ...
Copied!

my_ra_django_app/templates/signup.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
<h2>Sign up</h2>
6
<form method="post">
7
8
โ€‹
9
<div data-gb-custom-block data-tag="csrf_token">
10
โ€‹
11
{{ form.as_p }}
12
<button type="submit">Sign up</button>
13
</form>
14
โ€‹
15
</div>
Copied!

Test View

Let's create a view that uses user auth to test our system.

Python Decorators

Decorators are a syntax to call something like a helper function in Python. In the following example, we will use the @login_required decorator to trigger Django's built-in functionality to verify login before exposing the fruits view. Learn more about decorators here.โ€‹

my_ra_django_app/views.py

1
from django.contrib.auth.decorators import login_required
2
from django.http import HttpResponse
3
โ€‹
4
# ...
5
โ€‹
6
# set the built-in login required decorator w/ @
7
@login_required
8
def fruits(request):
9
return HttpResponse("Hello, banana!")
10
โ€‹
11
# ...
Copied!

Login

Template view files are not part of the built-in Django Auth system. We need to create them.
1
mkdir templates/registration
Copied!
Create the correctly named template files. Django has default names for all of the account urls mentioned above. Check here in each view to see the default template name for each view: https://docs.djangoproject.com/en/3.1/topics/auth/default/#all-authentication-viewsโ€‹
1
touch my_ra_django_app/templates/registration/login.html
2
touch my_ra_django_app/templates/registration/logged_out.html
Copied!
Note the use of the url name specified in urls.py (or in the default auth urls) like on line 18 when using the template url tag. See more about the template url tag here: https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#urlโ€‹

templates/registration/login.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
6
โ€‹
7
<div data-gb-custom-block data-tag="if">
8
โ€‹
9
<p>Your username and password didn't match. Please try again.</p>
10
11
โ€‹
12
</div>
13
โ€‹
14
15
โ€‹
16
<div data-gb-custom-block data-tag="if"></div>
17
โ€‹
18
19
โ€‹
20
<div data-gb-custom-block data-tag="if">
21
โ€‹
22
<p>Your account doesn't have access to this page. To proceed,
23
please login with an account that has access.</p>
24
25
โ€‹
26
<div data-gb-custom-block data-tag="else">
27
โ€‹
28
<p>Please login to see this page.</p>
29
30
โ€‹
31
</div>
32
โ€‹
33
34
โ€‹
35
</div>
36
โ€‹
37
<form method="post" action="
38
โ€‹
39
<div data-gb-custom-block data-tag="url" data-0='login'></div>">
40
<div data-gb-custom-block data-tag="csrf_token"></div>
41
โ€‹
42
<table>
43
<tr>
44
<td>{{ form.username.label_tag }}</td>
45
<td>{{ form.username }}</td>
46
</tr>
47
<tr>
48
<td>{{ form.password.label_tag }}</td>
49
<td>{{ form.password }}</td>
50
</tr>
51
</table>
52
<input type="submit" value="login" />
53
<input type="hidden" name="next" value="{{ next }}" />
54
</form>
55
โ€‹
56
{# Assumes you setup the password_reset view in your URLconf #}
57
<p><a href="
58
โ€‹
59
<div data-gb-custom-block data-tag="url" data-0='password_reset'>
60
โ€‹
61
">Lost password?</a></p>
62
โ€‹
63
</div>
Copied!

templates/registration/logged_out.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
<p>Logged out!</p>
6
<a href="
7
โ€‹
8
<div data-gb-custom-block data-tag="url" data-0='login'>
9
โ€‹
10
">Click here to login again.</a>
11
โ€‹
12
</div>
Copied!

Reset Password

Django comes with reset password functionality built-in. In order to use this functionality the user model would have to be changed to include email and/or change username to email so that Django would know where to send the reset password information.
1
touch my_ra_django_app/templates/registration/password_reset_form.html
2
touch my_ra_django_app/templates/registration/password_reset_done.html
3
touch my_ra_django_app/templates/registration/password_reset_email.html
4
touch my_ra_django_app/templates/registration/password_reset_confirm.html
5
touch my_ra_django_app/templates/registration/password_reset_complete.html
Copied!

templates/registration/password_reset_form.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
<form action="" method="post">
6
7
โ€‹
8
<div data-gb-custom-block data-tag="csrf_token">
9
โ€‹
10
11
โ€‹
12
<div data-gb-custom-block data-tag="if">
13
โ€‹
14
{{ form.email.errors }}
15
16
โ€‹
17
</div>
18
โ€‹
19
<p>{{ form.email }}</p>
20
<input type="submit" class="btn btn-default btn-lg" value="Reset password">
21
</form>
22
โ€‹
23
</div>
Copied!

templates/registration/password_reset_done.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block">
4
โ€‹
5
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
6
โ€‹
7
</div>
Copied!
Note that after this step you'll need to setup development mode email infrastructure. By default you can't see the emails that Django tries to send. More instructions on how to do that can be found here: https://docs.djangoproject.com/en/3.1/topics/email/#configuring-email-for-developmentโ€‹

templates/registration/password_reset_email.html

1
Someone asked for password reset for email {{ email }}. Follow the link below:
2
{{ protocol}}://{{ domain }}
3
โ€‹
4
<div data-gb-custom-block data-tag="url" data-0='password_reset_confirm' data-1='64' data-2='64' data-3='64' data-4='4'></div>
Copied!

templates/registration/password_reset_confirm.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
6
โ€‹
7
<div data-gb-custom-block data-tag="if"></div>
8
โ€‹
9
<p>Please enter (and confirm) your new password.</p>
10
<form action="" method="post">
11
12
โ€‹
13
<div data-gb-custom-block data-tag="csrf_token">
14
โ€‹
15
<table>
16
<tr>
17
<td>{{ form.new_password1.errors }}
18
<label for="id_new_password1">New password:</label></td>
19
<td>{{ form.new_password1 }}</td>
20
</tr>
21
<tr>
22
<td>{{ form.new_password2.errors }}
23
<label for="id_new_password2">Confirm password:</label></td>
24
<td>{{ form.new_password2 }}</td>
25
</tr>
26
<tr>
27
<td></td>
28
<td><input type="submit" value="Change my password" /></td>
29
</tr>
30
</table>
31
</form>
32
33
โ€‹
34
<div data-gb-custom-block data-tag="else">
35
โ€‹
36
<h1>Password reset failed</h1>
37
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
38
39
โ€‹
40
</div>
41
โ€‹
42
</div>
Copied!

templates/registration/password_reset_complete.html

1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block"></div>
4
โ€‹
5
<h1>The password has been changed!</h1>
6
<p><a href="
7
โ€‹
8
<div data-gb-custom-block data-tag="url" data-0='login'>
9
โ€‹
10
">log in again?</a></p>
11
โ€‹
12
</div>
Copied!

Further Reading