Advice on custom user model and custom auth serializers
I need some advice from the devs out there who are experienced in Django. I am relatively new to this framework and am working on a pharmacy management app with a Django-powered backend. I plan to use mobile number as the way to sign up into the app. Most built-in classes provide email as the default way to register and create new users. I am using DRF for the REST API stuff, dj-rest-auth and django-allauth for handling authentication. Right now I am working only on user accounts within the app. Could you please give a check and point out the mistakes. Any advice on the best practices would be appreciated.
Here's the custom user model
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager
from django.core.validators import RegexValidator
phone_validator = RegexValidator(regex=r"^[1-9]\d{9}$", message="Invalid Number")
class UserRole(models.TextChoices):
RETAILER = "RETAILER", "retailer"
STAFF = "STAFF", "staff"
class CustomUser(AbstractUser):
username = None
mobile = models.CharField(max_length=10, validators=[phone_validator], unique=True)
role = models.CharField(
max_length=20, choices=UserRole.choices, default=UserRole.STAFF
)
tenant = models.ForeignKey(
"tenants.Tenant",
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="users",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = CustomUserManager()
USERNAME_FIELD = "mobile"
REQUIRED_FIELDS = []
def __str__(self):
return f"{self.mobile} ({self.get_full_name()})"
Here are the custom serializers.
from dj_rest_auth.serializers import LoginSerializer
from dj_rest_auth.registration.serializers import RegisterSerializer
from rest_framework import serializers
from allauth.account.adapter import get_adapter
class MobileLoginSerializer(LoginSerializer):
username = None
mobile = serializers.CharField(required=True)
def validate(self, attrs):
attrs["username"] = attrs.get("mobile")
return super().validate(attrs)
class MobileRegisterSerializer(RegisterSerializer):
username = None
first_name = serializers.CharField()
last_name = serializers.CharField()
mobile = serializers.CharField()
pharmacy_name = serializers.CharField(write_only=True)
role = serializers.ChoiceField(choices=["RETAILER", "STAFF"])
def get_cleaned_data(self):
data = super().get_cleaned_data()
data.update(
{
"first_name": self.validated_data.get("first_name", ""),
"last_name": self.validated_data.get("last_name", ""),
"mobile": self.validated_data.get("mobile", ""),
"pharmacy_name": self.validated_data.get("pharmacy_name", ""),
"role": self.validated_data.get("role", ""),
}
)
return data
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
user = adapter.save_user(request, user, self, commit=False)
user.first_name = self.cleaned_data.get("first_name")
user.last_name = self.cleaned_data.get("last_name")
user.mobile = self.cleaned_data.get("mobile")
# user.pharmacy_name = self.cleaned_data.get("pharmacy_name")
user.role = self.cleaned_data.get("role")
user.save()
self.custom_signup(request, user)
return user
Here are the relevant code snippets from settings.py
...
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["dj_rest_auth.jwt_auth.JWTCookieAuthentication"]
}
REST_AUTH = {
"USE_JWT": True,
"JWT_AUTH_COOKIE": "access",
"JWT_AUTH_REFRESH_COOKIE": "refresh",
"JWT_AUTH_HTTPONLY": True,
"LOGIN_SERIALIZER": "accounts.serializers.MobileLoginSerializer",
"REGISTER_SERIALIZER": "accounts.serializers.MobileRegisterSerializer",
}
AUTH_USER_MODEL = "accounts.CustomUser"
ACCOUNT_USER_MODEL_USERNAME_FIELD = "mobile"
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = "username"
...
SITE_ID = 1
P.S.: I do not trust the AI responses. Different agents are suggesting different approaches and now I am confused.