Django 커스텀 유저

GisangLee·2022년 1월 30일
0

django

목록 보기
1/35
post-thumbnail

Django의 AbstractBaseUser를 커스텀해서 나만의 모델을 만들자

  1. accounts/models.py
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
  1. accounts/forms.py
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"]
  1. accounts/admin.py
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 = ()
  1. accounts/views.py
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)
  1. accounts/serializers.py
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를 할 수 있게 되었다.

앞으로도 유저 모델은 이렇게 하는 것이 좋을 거라 생각이 든다.

profile
포폴 및 이력서 : https://gisanglee.github.io/web-porfolio/

0개의 댓글