본문 바로가기
python

django 커스텀 유저 모델

by 초특급하품 2022. 2. 1.

처음 django 프로젝트를 설정하면 기본으로 설정되어있는 user 모델이 있다. 그래서 따로 user 모델을 추가하지 않더라도 python manage.py createsuperuser로 user 생성은 가능하다.

 

이렇듯 장고에는 숨겨진 기능들이 많은데, 사실 한눈에 잘 보이지 않을 뿐 없는 건 아니다. 가장 기본적인 사용자 모델을 코드 수준에서 눈으로 확인하고, AbstractUser, AbstractBaseUser을 사용해서 custom user model을 만드는 과정을 정리해본다.

 

지금 설정된 유저 모델은 무엇인가?

settings 파일 어디에도 그런 변수는 없을 수 있다. 그러면 global settings에 그 값이 있을 것이다. global settings는 pip로 설치한 django 패키지 내부 어딘가에 있을 테니 먼저 django 패키지부터 찾아야 한다.

 

파이썬 가상 환경에 따라 파일 구조가 다를 테니 python -c "import site; print(site.getsitepackages())"로 현재 참조되는 sitepacakges 경로를 확인한다. 해당 경로에 django/conf/global_settings.py를 열어보면 AUTH_USER_MODEL = 'auth.User'라는 설정값을 확인할 수 있다.

 

그렇다면 기본 유저 모델이 auth.User라는 것을 찾았으니 django/contrib/auth/models.py 에서 User class를 확인한다.

class User(AbstractUser):
    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

 

User class에서 속성으로 추가된 건 없고 AbstractUser를 상속받고, AbstractUser는 AbstractBaseUser를, AbstractBaseUser는 models.Model을 상속받는다. 각각 class에 선언된 변수만 살펴보면 다음과 같다.

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        validators=[username_validator],
    )
    first_name = models.CharField(_('first name'), max_length=150, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

 

 

class AbstractBaseUser(models.Model):
    password = models.CharField(_('password'), max_length=128)
    last_login = models.DateTimeField(_('last login'), blank=True, null=True)

    is_active = True

 

상속 구조를 알면 나중에 custom user model을 만들 때 어떤 class를 상속받아야 할지가 보인다. 아무튼 이렇게 상속으로 완성된 User 모델이 현재 기본으로 설정되어있다. 이 User 모델이 기본 설정이라는 값은 settings.py에서 확인할 수 있다. auth 관련된 앱이 이미 등록되어있을 것이다.

INSTALLED_APPS = [
  ...
  'django.contrib.auth',
  ...
]

 

 

기본 설정에서 python manage.py createsuerpuser로 관리자 유저를 생성하면 AbastractUser, AbstractBaseUser 속성들이 적용된 auth_user 테이블에 계정이 추가된다.

auth_user 테이블 정보

 


 

커스텀 유저 모델

python manage.py startapp myapp으로 유저 앱을 생성하고, 이 유저를 기본 사용자 모델로 변경을 해보자.

 

새로 생성한 myapp/models.py 에 아래와 같이 id, email을 가지는 커스텀 유저 모델을 정의했다. 유저 모델 생성을 관리하는 Manager도 같이 만들어야 한다. Manager는 일반 유저와 관리자 유저를 생성하는 create_user, create_superuesr 두 함수를 추가한다.

 

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.base_user import BaseUserManager
from django.core.validators import validate_email
from django.db import models
import uuid


class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not(email):
            raise ValueError('Email required')

        email = self.normalize_email(email)
        validate_email(email)

        user, created = self.model.objects.get_or_create(email=email, **extra_fields)

        if created and password:
            user.set_password(password)
            user.save(using=self._db)

        return user

    def create_superuser(self, email, password):
        user = self.create_user(email=email, password=password)
        user.is_superuser = True
        user.is_staff = True

        user.save(using=self._db)

        return user


class User(AbstractBaseUser, PermissionsMixin):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.CharField(unique=True, max_length=255)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    
    objects = UserManager()

    USERNAME_FIELD = 'email'

 

이렇게 새로 작성한 유저 모델을 쓰기 위해 전역으로 설정되어있던 AUTH_USER_MODEL 값을 settings.py에서 다시 쓴다.

AUTH_USER_MODEL = 'myapp.User'

 

makemigrations && migrate로 디비에 스키마를 반영하면 이제 myapp_user 테이블에 커스텀 유저 모델로 생성한 필드들이 보인다. 이 과정을 그대로 해봤으면 알겠지만 AUTH_USER_MODEL을 auth_user에서 커스텀 유저 모델로 바꾸는 과정에 다른 의존성들이 엮여있어서 migration에 실패한다. 개발 단계라면 싹 지우고 다시 하면 되겠지만, 영 좋지 못한 방법이다. 따라서 프로젝트 처음부터 AbstractBaseUser을 상속받아 커스텀 유저 모델을 만드는 것부터 시작하는 게 좋아 보인다.

'python' 카테고리의 다른 글

django rest framework의 serializer, view 추상화 과정  (0) 2020.06.25
django model 정리  (0) 2020.06.13
cookiecutter로 django 프로젝트 생성  (0) 2020.06.11
Python 개발 가상환경 설정  (0) 2019.10.20

댓글