Skip to content

Commit

Permalink
Add CustomUser model and Update dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
erfanghorbanee committed Aug 26, 2024
1 parent 4c52c3e commit 9cfb2f2
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 7 deletions.
5 changes: 5 additions & 0 deletions Django-Shop/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"allauth.socialaccount",
'allauth.socialaccount.providers.google',

"phonenumber_field",

# custom apps
"home",
"users",
Expand Down Expand Up @@ -160,3 +162,6 @@
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# Custom user model
AUTH_USER_MODEL = "users.CustomUser"
32 changes: 32 additions & 0 deletions Django-Shop/users/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.contrib.auth.base_user import BaseUserManager


class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifier for authentication.
"""

def create_user(self, email, password=None, **extra_fields):

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)

# using=self._db ensures that the user is saved to the correct database associated with the user manager.
user.save(using=self._db)
return user

def create_superuser(self, email, password=None, **extra_fields):
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)
148 changes: 148 additions & 0 deletions Django-Shop/users/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Generated by Django 5.1 on 2024-08-26 05:40

import django.core.validators
import django.utils.timezone
import phonenumber_field.modelfields
import users.models
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="CustomUser",
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, verbose_name="email address"
),
),
(
"phone",
phonenumber_field.modelfields.PhoneNumberField(
max_length=128, region=None
),
),
(
"profile_picture",
models.ImageField(
blank=True,
null=True,
upload_to="profile_pics/",
validators=[
django.core.validators.FileExtensionValidator(
["jpg", "jpeg", "png"]
),
users.models.validate_image_size,
],
),
),
(
"gender",
models.CharField(
choices=[
("M", "Male"),
("F", "Female"),
("O", "Other"),
("X", "Prefer not to say"),
],
default="X",
max_length=1,
),
),
(
"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,
},
),
]
56 changes: 55 additions & 1 deletion Django-Shop/users/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.core.validators import FileExtensionValidator
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
from .managers import CustomUserManager

# Create your models here.

def validate_image_size(image):
file_size = image.file.size
limit_mb = 2
if file_size > limit_mb * 1024 * 1024:
raise ValidationError(f"Max size of file is {limit_mb} MB")


class CustomUser(AbstractUser):
username = None
email = models.EmailField(("email address"), unique=True)
USERNAME_FIELD = "email"

# will be required when creating a superuser.
REQUIRED_FIELDS = ["first_name", "last_name"]

objects = CustomUserManager()
phone = PhoneNumberField(null=False, blank=False)

# TODO: Process image before saving
profile_picture = models.ImageField(
upload_to="profile_pics/",
validators=[
FileExtensionValidator(["jpg", "jpeg", "png"]),
validate_image_size,
],
null=True,
blank=True,
)

MALE = "M"
FEMALE = "F"
OTHER = "O"
PREFER_NOT_TO_SAY = "X"

GENDER_CHOICES = [
(MALE, "Male"),
(FEMALE, "Female"),
(OTHER, "Other"),
(PREFER_NOT_TO_SAY, "Prefer not to say"),
]

gender = models.CharField(
max_length=1,
choices=GENDER_CHOICES,
default=PREFER_NOT_TO_SAY,
)

def __str__(self):
return self.email
9 changes: 5 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
python-slugify==8.0.4
pillow==10.3.0
whitenoise==6.6.0
pillow==10.4.0
whitenoise==6.7.0
django-phonenumber-field[phonenumbers]==8.0.0

# Django
# ------------------------------------------------------------------------------
Django==5.0.6
django-allauth[socialaccount]==0.62.1
Django==5.1
django-allauth[socialaccount]==64.1.0
4 changes: 2 additions & 2 deletions requirements/local.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ psycopg==3.1.19

# Testing
# ------------------------------------------------------------------------------
pytest==8.2.0
pytest==8.3.2

# Code quality
# ------------------------------------------------------------------------------
ruff==0.4.4
ruff==0.6.2

0 comments on commit 9cfb2f2

Please sign in to comment.