This post will demonstrate the necessary step's that you will need to follow when you want to build authentication system with you Django framework using the built-in user authentication system. You
can get the code of this project on github
Start with clean work space where Django app is going to live
mkdir news-wire
cd news-wire
Time to setup virtual eviroment, install django and kickoff the project
python3 -m venv venv
source venv/bin/activate
pip3 install Django
django-admin startproject news_art
House keeping
mv news_art/manage.py ./
mv news_art/news_art/* news_art/
rm -r news_art/news_art/
nano news_art/settings.py
ALLOWED_HOSTS = ['*']---------- We want to acsses our app from anywhere
Django automatically installs the
auth
app when a new project is created. This can be reveled in the settings.py
under INSTALLED_APPS
and you can see auth
is one of several built-in apps Django has installed.INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth', ----------------------This one
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
python3 manage.py migrate
python3 manage.py runserver 192.168.0.245:8000
To use the
auth
app we need to add it to our project-level urls.py
file. Make sure to add include
on the second line. I’ve chosen to include the auth
app at accounts/
but you can use any url pattern you want.nano news_art/urls.py
from django.contrib import admin
from django.urls import path, include # add this
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')), # new
]
Login Page
Django by default will look within a templates folder calledregistration
for auth templates. The login template is called login.html
.
mkdir -p templates/registration
Update the
settings.py
file to tell Django to look for a templates
folder at the project level. Update the DIRS
setting within TEMPLATES
as follows.nano news_art/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
We need to specify where to redirect the user upon a successful login. We use the
LOGIN_REDIRECT_URL=reverse_lazy
setting to specify this route. At the bottom of the settings.py
file add the following to redirect the user to the homepage."We are using
reverse_lazy()
to build the URLs dynamically. The reverse_lazy()
function reverses URLs just like reverse()
does, but you can use it when you need to reverse URLs before your project's URL configuration is loaded."
from django.urls import reverse_lazy
LOGIN_REDIRECT_URL=reverse_lazy('home')
LOGIN_URL=reverse_lazy('login')
LOGOUT_REDIRECT_URL = 'home'
Now update the project-level urls.py
file so we
can display the homepage. On the third line, import
TemplateView
and then add a
urlpattern
for it.
nano news_art/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('', TemplateView.as_view(template_name='home.html'), name='home'), # new
]
from django.urls import path, include
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('', TemplateView.as_view(template_name='home.html'), name='home'), # new
]
Create Template:
create new
base.html
, home.html
and login.html
files. Note that base.html
and home.html
these are located within the templates
folder but not within templates/registration/
where Django auth looks by default for user auth templates, login.html
.
Base template
nano templates/base.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}Django Authentication{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
</head>
<body>
<div class="container">
{% block content %}{% endblock %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>
For the home template
nano templates/home.html
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Hi {{ user.username }}!
<p><a href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>You are not logged in</p>
<a href="{% url 'login' %}">login</a>
{% endif %}
{% endblock %}
Login template
nano templates/registration/login.html
{% extends 'base.html' %}
{% block title %} | Account Login {% endblock %}
{% block content %}
<section id="login" class="bg-light py-5">
<div class="container">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card">
<div class="card-header bg-primary text-white">
<h4>
<i class="fas fa-sign-in-alt"></i> Login</h4>
</div>
<div class="card-body">
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="form-group">
<label for="password2">Password</label>
<input type="password" name="password" class="form-control" required>
</div>
<input type="submit" value="Login" class="btn btn-secondary btn-block">
</form>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
Done!. If you start the Django server again with
python3 manage.py runserver 192.168.0.245:8000
and navigate to the homepage at http://192.168.0.245:8000/ you’ll see the following:Create users
But there’s one missing piece: we haven’t created any users yet. It's possible to create a superuser account from the command line.But for the sake of this post I wont go through that route however I’ll demostrate how to add a signup page to register new users to the Django app.Time to create a signup page so users can register for a new account.
Users app
Since we’re making our own view and url for registration, we need to create a dedicated app. Let’s call itaccounts
.django-admin startapp accounts
Make sure to add the new app to the
INSTALLED_APPS
setting
file:nano news_art/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts',------------------------------ # New
]
Then add a project-level url for the
accounts
app above our included Django auth
app. nano news_art/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')), # new
path('accounts/', include('django.contrib.auth.urls')),
path('', TemplateView.as_view(template_name='home.html'), name='home'),
]
Create a new
urls
file in our accounts
app. Note that we are importing a view called register
nano accounts/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('register', views.register, name='register'),
]
For the
views.py
file add the followingnano accounts/views.py
from django.shortcuts import render, redirect
from django.contrib import messages, auth
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
# Get form values
first_name = request.POST['first_name']
last_name = request.POST['last_name']
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
password2 = request.POST['password2']
# Check if passwords match
if password == password2:
# Check username
if User.objects.filter(username=username).exists():
messages.error(request, 'That username is taken')
return redirect('register')
else:
if User.objects.filter(email=email).exists():
messages.error(request, 'That email is being used')
return redirect('register')
else:
# Looks good
user = User.objects.create_user(username=username, password=password,email=email, first_name=first_name, last_name=last_name)
user.save()
messages.success(request, 'You are now registered and can log in')
return redirect('login')
else:
messages.error(request, 'Passwords do not match')
return redirect('register')
else:
return render(request, 'accounts/register.html')
Create a template
signup.html
mkdir templates/accounts
nano templates/accounts/register.html
{% extends 'base.html' %}
{% block title %} | Register Account {% endblock %}
{% block content %}
<section id="register" class="bg-light py-5">
<div class="container">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card">
<div class="card-header bg-primary text-white">
<h4>
<i class="fas fa-user-plus"></i> Register</h4>
</div>
<div class="card-body">
<form action="{% url 'register' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="first_name">First Name</label>
<input type="text" name="first_name" class="form-control" required>
</div>
<div class="form-group">
<label for="last_name">Last Name</label>
<input type="text" name="last_name" class="form-control" required>
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="form-group">
<label for="password2">Password</label>
<input type="password" name="password" class="form-control" required>
</div>
<div class="form-group">
<label for="password">Confirm Password</label>
<input type="password" name="password2" class="form-control" required>
</div>
<input type="submit" value="Register" class="btn btn-secondary btn-block">
</form>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
Open the home.html template after
<a href="{% url 'login' %}">login</a>
or
<a href="{% url 'register' %}">register</a>
------- add the followingTo confirm that it works, spin up the server with
python3 manage.py runserver 192.168.0.245:8000
and navigate to http://192.168.0.245:8000.Clink on the register link to create you'r very first user account
You should be redirected to the login page after sucssefuly registed an account proceed with login
After a sucsseful login you should be redirected to home page