Skip to content

Commit

Permalink
Feature/add user model (#12)
Browse files Browse the repository at this point in the history
Add custom user model

* Manage admin panel
* Add migration file of user model
* Rename pull request template name
  • Loading branch information
sudan45 committed Sep 13, 2024
1 parent b011616 commit ef04ede
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 0 deletions.
2 changes: 2 additions & 0 deletions main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"user",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -112,6 +113,7 @@
},
}

AUTH_USER_MODEL = "user.User"

# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
Expand Down
Empty file added user/__init__.py
Empty file.
57 changes: 57 additions & 0 deletions user/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.utils.translation import gettext_lazy as _

from .models import User


@admin.register(User)
class UserAdmin(DjangoUserAdmin):
list_display = ("email", "first_name", "last_name", "is_staff")
list_filter = ("is_staff", "is_superuser", "is_active", "groups")
search_fields = ("first_name", "last_name", "email")
ordering = ("email",)

fieldsets = (
(
None,
{
"fields": (
"email",
"password",
)
},
),
(
_("Personal info"),
{
"fields": (
"first_name",
"last_name",
"department",
)
},
),
(
_("Permissions"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
),
},
),
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": ("email", "password1", "password2"),
},
),
)
6 changes: 6 additions & 0 deletions user/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class UserConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "user"
35 changes: 35 additions & 0 deletions user/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _


class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""

def create_user(self, email, password, **extra_fields):
"""
Create and save a user with the given email and password.
"""
if not email:
raise ValueError(_("The Email must be set"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user

def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)

if extra_fields.get("is_staff") is not True:
raise ValueError(_("Superuser must have is_staff=True."))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must have is_superuser=True."))
return self.create_user(email, password, **extra_fields)
84 changes: 84 additions & 0 deletions user/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Generated by Django 5.1 on 2024-09-11 05:48

import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
]

operations = [
migrations.CreateModel(
name="User",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("password", models.CharField(max_length=128, verbose_name="password")),
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")),
("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")),
("email", models.EmailField(max_length=254, unique=True)),
(
"display_name",
models.CharField(blank=True, max_length=255, verbose_name="system generated user display name"),
),
("user_type", models.PositiveSmallIntegerField(choices=[(1000, "HR")], null=True)),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
),
]
18 changes: 18 additions & 0 deletions user/migrations/0002_alter_user_user_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2024-09-12 05:54

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("user", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="user",
name="user_type",
field=models.PositiveSmallIntegerField(choices=[(1, "HR")], null=True),
),
]
18 changes: 18 additions & 0 deletions user/migrations/0003_rename_user_type_user_department.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2024-09-13 09:07

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("user", "0002_alter_user_user_type"),
]

operations = [
migrations.RenameField(
model_name="user",
old_name="user_type",
new_name="department",
),
]
Empty file added user/migrations/__init__.py
Empty file.
33 changes: 33 additions & 0 deletions user/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _

from .managers import CustomUserManager


# Create your models here.
class User(AbstractUser):
class Department(models.IntegerChoices):
HR = 1, _("HR")

EMAIL_FIELD = USERNAME_FIELD = "email"
REQUIRED_FIELDS = []

username = None
email = models.EmailField(unique=True)
display_name = models.CharField(
verbose_name=_("system generated user display name"),
blank=True,
max_length=255,
)
department = models.PositiveSmallIntegerField(choices=Department.choices, null=True)

objects: CustomUserManager = CustomUserManager()

def save(self, *args, **kwargs):
# Make sure email are store in lowercase
self.email = self.email.lower()
if self.pk is None:
super().save(*args, **kwargs)
self.display_name = self.get_full_name() or f"User#{self.pk}"
return super().save(*args, **kwargs)
1 change: 1 addition & 0 deletions user/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Create your tests here.
1 change: 1 addition & 0 deletions user/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Create your views here.

0 comments on commit ef04ede

Please sign in to comment.