STAY INFORMED
following content serves as a personal note and may lack complete accuracy or certainty.

Minimal-Mistakes instruction
Useful vscode Shortcut Keys
Unix Commands
npm Commands
Vim Commands
Git Note
Useful Figma Shortcut Keys

3 minute read

Setup

mkdir share-hub
cd share-hub
pyenv virtualenv 3.7.13 django_shareHub_env
pip3 install django==2.2
pyenv local django_shareHub_env
django-admin startproject shareHub_project
cd shareHub_project
python manage.py startapp shareHub
# settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'shareHub',
]

Create User Model

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

Additionally, for an user model, you need to add ‘AUTH_USER_MODEL = “[app-name].User’” to settings.py at very bottom.

# settings.py

AUTH_USER_MODEL = 'shareHub.User'

Register Model to Admin Page

# admin.py

from django.contrib import admin
from .models import User
from django.contrib.auth.admin import UserAdmin

admin.site.register(User, UserAdmin)

UserAdmin includes all necessary fields and functionalities, like handling permissions and user information.

Create Super User

python manage.py createsuperuser
# type your info

Django-allauth

There are several things to install for user authentication.

more info about installation

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'shareHub',

    # need to install
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
]

.
.
.

AUTHENTICATION_BACKENDS = [
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by email
    'allauth.account.auth_backends.AuthenticationBackend',
]

# Email settings

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

and add url patterns.

# urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("allauth.urls")),
]

Now login page is added. If you go to localhost:8000/login,

des1

and migrate it since model has been changed.

python manage.py makemigrations
python manage.py migrate

Login / Logout

Setup

First, add path for shareHub app.

# project/urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('shareHub.urls')),
    path('', include("allauth.urls")),
]
# shareHub/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]
# views.py

from django.shortcuts import render

def index(request):
    return render(request, 'shareHub/index.html')

This redirects to index page from login page after user login.

# settings.py

# set index page before user login
ACCOUNT_SIGNUP_REDIRECT_URL = 'index' 
LOGIN_REDIRECT_URL = 'index'

And there are some several thing need to set for handling session, signup, etc.

ACCOUNT_LOGOUT_ON_GET = True # makes logout without asking
ACCOUNT_AUTHENTICATION_METHOD = 'email' # makes user can login with email
ACCOUNT_EMAIL_REQUIRED = True # email is required when signup
ACCOUNT_USERNAME_REQUIRED = False # you won't see username input when signup
# ACCOUNT_SESSION_REMEMBER = True # Computer will remember user without checking 'remember me' checkbox
SESSION_COOKIE_AGE = 3600 # set cookie valid time to an hour (default is 2 weeks)
ACCOUNT_PASSWORD_INPUT_RENDER_VALUE = True # makes the password field show the entered password

more info about allauth setting

Session

When user logout manually, session is automatically deleted but when cookie is expired and user was logged out, session is not deleted. You need to delete it manually, or automatize it. Otherwise, lots of memory will be stacked.

python manage.py clearsessions

Render Page Depending On Login/Logout

is_authenticated return true / false depending user is logged in / out. And the url is from allauth.

more info about allauth urls

<navbar>
    {% if user.is_authenticated %}
        <a href={% url 'account_logout' %}>logout</a>
        {% else %}
        <a href={% url 'account_login' %}>sign in</a>
        <a href={% url 'account_signup' %}>sign up</a>
    {% endif %}
</navbar>

<h1>homepage</h1>

{% if user.is_authenticated %}
    <p>Hello {{user}}</p>
        <p>Email: {{user.email}}</p>
{% else %}
    <p>need to login</p>
{% endif %}

des2

des3

Signup Form

There is default signup form, and you can add what you want from user’s info like nickname and so on.

# forms.py 

from django import forms
from .models import User

class SignupForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['nickname']

    def signup(self, request, user):
        user.nickname = self.cleaned_data['nickname']
        user.save()
# settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'shareHub.forms.SignupForm'

And add nickname field to models.py as well.

# models.py 
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    nickname = models.CharField(
        max_length=15, 
        unique=True, 
        null=True, 
        error_messages={"unique": "This nickname already exists."})

    def __str__(self):
        return self.email

des4

Password validator

There is default setting for password validator,

# setting.py

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

But you can create your own validator.

AUTH_PASSWORD_VALIDATORS = [
    "NAME": "shareHub.validators.CustomPasswordValidator",
]
# validators.py

import string
from django.core.exceptions import ValidationError


def contains_special_character(value):
    for char in value:
        if char in string.punctuation: # check punctuation is included
            return True
    return False


def contains_uppercase_letter(value):
    for char in value:
        if char.isupper():
            return True
    return False

def contains_lowercase_letter(value):
    for char in value:
        if char.islower():
            return True
    return False

def contains_number(value):
    for char in value:
        if char.isdigit():
            return True
    return False


class CustomPasswordValidator:
    def validate(self, password, user=None):
        if (
            len(password) < 8 or
            not contains_uppercase_letter(password) or
            not contains_lowercase_letter(password) or
            not contains_number(password)
        ):
            raise ValidationError("Your password must contain at least 8 characters.")
        
    def get_help_text(self):
        return "Your password must contain at least 8 characters."
    

def validate_no_special_characters(value):
    if contains_special_character(value):
        raise ValidationError("Cannot be included punctuations.")