Django — custom user authentication
-
Back-End
Initiate a python virtual environment and start a new project:
python -m venv env source env/bin/activate pip install Django pip install django-crispy-forms # for nice forms mkdir custom_auth cd custom_auth django-admin startproject src . python manage.py startapp accounts python manage.py runserver
We do not migrate until the configuration of custom user which will be designed by subclassing AbstractUser which subclasses AbstractBaseUser.
Update /src/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'accounts',
]
...
AUTH_USER_MODEL = 'accounts.CustomUser'
Update ‘/accounts/models.py’
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
# add additional fields in here
description = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.username
Update ‘/accounts/forms.py’
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'description')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'description')
Update ‘/src/admin.py’ since Admin is linked to the users definitions.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username',]
admin.site.register(CustomUser, CustomUserAdmin)
Run:
python manage.py makemigrations python manage.py migrate
Create superuser:
python manage.py createsuperuser
Update /src/settings.py adding:
TEMPLATES = [
{
...
'DIRS': [str(BASE_DIR.joinpath('templates'))],
...
},
]
...
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'
Create directory ‘custom_auth/templates/registration’ and edit ‘/templates/base.html’ (using Bootstrap 4 starter template):
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>{% block title %}Django Auth Tutorial{% endblock %}</title>
</head>
<body>
<div class="container">
<main>
{% block content %}
{% endblock %}
</main>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
Create ‘/templates/home.html’
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Hi {{ user.username }}!
<p><a href="{% url 'logout' %}">Log Out</a></p>
{% else %}
<p>You are not logged in</p>
<a href="{% url 'login' %}">Log In</a> |
<a href="{% url 'signup' %}">Sign Up</a>
{% endif %}
{% endblock %}
‘/templates/registration/login.html’
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Log In</h2>
<form method="post">
{% csrf_token %}
{% comment %}{{ form.as_p }}{% endcomment %}
{{ form|crispy }}
<button type="submit">Log In</button>
</form>
{% endblock %}
‘/templates/registration/signup.html’
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Sign Up{% endblock %}
{% block content %}
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{% comment %}{{ form.as_p }}{% endcomment %}
{{ form|crispy }}
<button type="submit">Sign Up</button>
</form>
{% endblock %}
Update ‘/src/urls.py’
from django.contrib import adminfrom django.urls import path, includeurlpatterns = [
path('admin/', admin.site.urls),
path('', include('accounts.urls')),
path('accounts/', include('django.contrib.auth.urls')),
]
Create ‘/accounts/urls.py’
from django.urls import pathfrom . import viewsurlpatterns = [
path('', views.home, name = 'home'),
path('accounts/signup/', views.signup, name='signup'),
]
Update ‘/accounts/views.py’
from django.shortcuts import render
def home(request):
return render(request, 'home.html', {})
from django.urls import reverse
from django.shortcuts import redirect
from .forms import CustomUserCreationForm
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse("login"))
else:
return redirect(reverse("home"))
form = CustomUserCreationForm()
return render(request, "registration/signup.html", {"form":form})
Access ‘localhost:8000’.
The end.