Django의 AbstractBaseUser를 커스텀해서 나만의 모델을 만들자
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
)
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, username, email, **extra_fields):
try:
user = self.model(
email=self.normalize_email(email), username=username, **extra_fields
)
return user
except Exception as e:
print("CREATE USER ERROR : ", e)
def create_superuser(self, username, email=None, password=None, **extra_fields):
superuser = self.create_user(
username=username, email=self.normalize_email(email)
)
superuser.is_superuser = True
superuser.is_admin = True
superuser.is_active = True
superuser.is_staff = True
superuser.set_password(password)
superuser.save(using=self.db)
return superuser
class User(AbstractBaseUser):
objects = UserManager()
GENDER_MALE = "Male"
GENDER_FEMALE = "Female"
GENDER_CHOICES = ((GENDER_MALE, "Male"), (GENDER_FEMALE, "Female"))
username = models.CharField(max_length=20, unique=True)
email = models.EmailField(max_length=100)
gender = models.CharField(choices=GENDER_CHOICES, blank=True, max_length=10)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = "username"
def __str__(self):
return self.email
def has_module_perms(self, app_label):
# return self.is_admin
return True
def has_perm(self, perm, obj=None):
# return self.is_admin
return True
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.utils.translation import ugettext_lazy as _
from . import models as user_models
class UserCreationForm(forms.ModelForm):
# 사용자 생성 폼
email = forms.EmailField(
label=_("Email"),
required=True,
widget=forms.EmailInput(
attrs={
"class": "form-control",
"placeholder": _("Email address"),
"required": "True",
}
),
)
username = forms.CharField(
label=_("Username"),
required=True,
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": _("Username"),
"required": "True",
}
),
)
password1 = forms.CharField(label="Password", widget=forms.PasswordInput)
password2 = forms.CharField(
label="Password confirmation", widget=forms.PasswordInput
)
class Meta:
model = user_models.User
fields = (
"email",
"username",
)
def clean_password2(self):
# 두 비밀번호 입력 일치 확인
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.email = user_models.UserManager.normalize_email(self.cleaned_data["email"])
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
# 비밀번호 변경 폼
password = ReadOnlyPasswordHashField(label=_("Password"))
class Meta:
model = user_models.User
fields = ("email", "password", "is_active", "is_superuser")
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from . import forms
from . import models as user_models
# Register your models here.
@admin.register(user_models.User)
class CustomUserAdmin(BaseUserAdmin):
form = forms.UserChangeForm
add_form = forms.UserCreationForm
list_display = (
"pk",
"email",
"username",
)
list_filter = ("is_admin",)
fieldsets = (
(
None,
{
"fields": (
"email",
"password",
),
},
),
("Permissions", {"fields": ("is_admin",)}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": ("email", "username", "password1", "password2"),
},
),
)
filter_horizontal = ()
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from . import serializers
# Create your views here.
class SignupView(APIView):
def post(self, request, format=None):
serializer = serializers.SignupSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
from rest_framework import serializers
from . import models as user_models
class SignupSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
if validated_data["email"]:
req_password = validated_data.pop("password")
user = user_models.User.objects.create_user(**validated_data)
user.set_password(req_password)
user.save()
print("CREATED USER : ", user)
return user
class Meta:
model = user_models.User
fields = "__all__"
이로서 가장 기본적인 AbstractBaseUser를 상속받아서
Fully Customize를 할 수 있게 되었다.
앞으로도 유저 모델은 이렇게 하는 것이 좋을 거라 생각이 든다.