유저 커스텀 모델 사용하기
Django에서는 유저 모델을 기본적으로 제공하고 있다. django.contrib.auth.models.User에 보면 장고의 유저 모델은 다음과 같이 명시되어 있다.
📁 django.contrib.auth.models.User
class User(AbstractUser):
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
아래는 User 모델에서 사용하고 있는 속성들이다.
username = models.CharField()
first_name = models.CharField()
last_name = models.CharField()
email = models.EmailField()
is_staff = models.BooleanField()
is_active = models.BooleanField()
date_joined = models.DateTimeField()
우리는 해당 장고에서 주는 유저 모델을 그대로 쓸 것인지, 커스텀해서 사용할 것인지, 아예 사용하지 않고 새로운 유저 모델을 만들어 사용할 것인지에 대해 고민할 필요가 있다. 일반적으로 3가지 확장 방법을 이용하여 장고 유저 모델을 사용하는 편이다.
- 표준 User 모델과 1대 1 관계를 가지는 모델을 만드는 방법
- AbstractUser을 상속받는 모델을 만드는 방법
- AbstractBaseUser을 상속받는 모델을 만드는 방법
표준 User 모델과 1대1 관계를 가지는 모델을 만드는 방법
해당 방법은 표준 User 모델과 1대1 관계를 가지는 모델을 만들어 유저 정보를 추가하고 싶은 정보를 쓴다.
class UserAddInfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
department = models.CharField()
image = models.ImageField()
하지만 해당 방법은 장고의 기본 속성을 반드시 이용하여야 하며, email로 로그인할 수 있 도록 변경할 수 없다. 또한 테이블이 여러개로 나뉘기 때문에 성능면 에서도 봤을때도 좋지 않기에, 크게 추천하지 않는 방식이다.
AbstarctUser을 상속한 모델을 만드는 방법
AbstaractUser은 표준 User 모델이 상속하여 이용하는 방법이다. AbstractUser 모델은 django.contrib.auth.models에 다음과 같이 정의되어 있다.
📁 AbstaractUser
class AbstractUser(AbstractBaseUser, PermissionsMixin):
# 기본 제공 속성
username_validator = UnicodeUsernameValidator()
username = models.CharField(_('username'), max_length=150, unique=True,…)
first_name = models.CharField(_('first name'), max_length=30, 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 Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = True
AbstaractUser은 AbstaractUser과 PermissionMixin을 상속받고 있다. 해당 방법은 테이블이 여러 개로 나뉘어 퍼포먼스가 나빠지는 등의 불편함은 없지만, 원래 있던 장고 유저모델에서 속성값을 추가만 하여 사용함으로써 모델의 유연성이 낮다. 만약 원래 장고 유저 모델에서 칼럼만을 추가하고 싶은 경우에는 이 방법을 추천한다.
AbstarctBaseUser을 상속한 모델을 만드는 방법
AbstractBaseUser은 django.contrib.auth.base_user에 다음과 같이 정의되어 있다.
📁 AbstractBaseUser
class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128)
last_login = models.DateTimeField(_('last login'), blank=True, null=True)
is_active = True
REQUIRED_FIELDS = []
_password = None
class Meta:
abstract = True
AbstractBaseUser은 django.db.models.Model 상속 받고 있다. AbstractBaseUser는 기본적으로 비밀번호 필드가 존재하며, 비밀번호 해시화(set_password), 비밀번호 변경, 재설정의 기본적인 인증 기능을 제공한다. 이것을 이용하여 유저 모델을 커스텀해서 사용하게 되면 다음과 같이 작성이 가능하다.
📁 models.py
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin,
)
from core.models import TimeStampedModel
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("email must have not blank")
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email, password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
class Meta:
db_table = "User"
- BaseUserManager: 장고에서 사용자 모델을 커스터마이징 할 때 사용하는 관리자 클래스로, 사용자 모델을 생성하고 관리하는 데 필요한 메소드를 제공한다. (예 : create_user, create_superuser) 현재 코드에서 UserManager은 BaseUserManager을 상속받은 다음 해당 함수를 오버라이딩한 상태이다.
- is_active : 사용자가 "활성"으로 간주되는지 여부를 나타내는 Bool 속성
- is_staff : 스태프 권한
- obejcts: 사용자 모델을 생성하고 관리하는 매니저를 설정하기 위한 변수이다. 위에 정의한 UserManager()을 지정한다.
- USERNAME_FIELD: 어떤 속성을 기준으로 로그인 할 것인지에 대한 값이다. 기준이 되는 값은 항상 유니크(unique)로 설정되어야 한다.
(중요) 커스텀 유저 모델을 정의한 뒤
1. 마이그레이션 문제
커스텀 유저 모델을 정의한 뒤에는 바로 마이그레이션을 해선 안된다. 그렇게 되면 우리가 설정한 유저 모델이 아닌, 장고에서 기본적으로 제공하는 유저 모델을 가지고 마이그레이션이 진행되기 때문에, 스키마가 꼬여 버린다. 그렇게 되면 아래와 같은 오류를 마주하게 됨으로 주의하기 바란다.
ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'accounts.account', but app 'accounts' doesn't p
상황 django에서 유저 모델을 만들어서 migrate하는 도중에 해당 오류가 발생하였다. 해결 https://stackoverflow.com/questions/50324561/valueerror-the-field-admin-logentry-user-was-declared-with-a-lazy-reference ValueError: The fiel
jheaon.tistory.com
제일 좋은 방법은 프로젝트를 진행 할 때, 항상 유저 모델을 먼저 정의하고 가는 것이다. 위의 유저 커스텀 모델을 작성했다면, 프로젝트 폴더의 settings.py에 유저 커스텀 모델을 등록한다.
📁 settings.py
AUTH_USER_MODEL = 'users.User'
이렇게 등록하게 된다면, 사용자가 정의한 유저 모델을 사용할 수 있게 된다.
2. 유저 생성 문제
우리가 만든 유저를 생성하기 위해서는, User.obejcts.craete()가 아닌 User.obejcts.create_user()을 사용해두어야 한다. (create_user() 함수는 위에서 작성한 UserManager의 메소드입니다. 다른 메소드로 정의했다면 해당 메소드를 사용하시면 됩니다.) 그렇게 저장하지 않는다면, 유저가 생성될 때 비밀번호가 암호화 되지 않고 데이터베이스에 저장됨으로 주의하자!
'FrameWork > Django' 카테고리의 다른 글
장고 개발 환경에서 프로세스 2개가 실행되는 이유 (1) | 2024.10.07 |
---|---|
Django에서 static, media 관리하기 (0) | 2024.07.29 |
N + 1 쿼리 문제 (0) | 2024.07.10 |
select_related와 prefetch_related (0) | 2024.07.10 |
orm과 queryset (0) | 2024.07.10 |