글에 앞서, User 모델 작성에 많은 도움을 준 포스팅 두 개를 먼저 소개하고자 한다!
How to extend Django User Model
첫 번째 글에서 확인할 수 있지만,
Django에서 User 모델을 확장하는 방법은 크게 4가지 정도로 나뉜다!
1. Proxy Model 사용하기
2. User 모델과 One-To-One 연결하기
3. AbstractUser 사용하기
4. AbstractBaseUser 사용하기
필자는 처음엔 별 생각없이... 저번에 들었던 Udemy 인강을 따라서
4번 방법인 AbstractBaseUser를 상속받아 User 모델을 짜려고 했다.
그러다가.. 어쩌다 보니 2, 3, 4번 방법을 모두 한 번씩 써 보는 삽질을 거쳐...
현재로서는 다시 AbstractBaseUser 사용에 정착한 상태이다.
AbstractBaserUser는 기본적으로 제공하는 필드의 가짓수가 상대적으로 적어,
필요한 필드만 작성해서 사용하기 좋지만,
그만큼 직접 작성해 줘야 하는 것도 많은 편이라고 한다.
(BaseUserManager를 상속하는 UserManager 등...??)
1) 팀원들과의 회의 결과 email을 username으로 활용하자는 쪽으로 논의가 기울었고
2) 그렇게 설정하려다 보니 createsuperuser 함수를 커스터마이징하지 않으면 에러가 났기 때문이다..
backend/account/models.py
from django.contrib.auth.base_user import BaseUserManager
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, \
PermissionsMixin
from django.contrib.auth.models import AbstractUser
from django.conf import settings
from django.db.models.fields import BooleanField
from django.db.models.fields.related import OneToOneField
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserManager(BaseUserManager):
# 유저 생성 helper function 제공. user 생성할 때의 행위를 지정
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('email 필수 입력!')
user = self.model(email=self.normalize_email(email), **extra_fields)
#self.model => UserManager가 속해 있는 모델에 접근
#normalize_email로 도메인 부분 lowercase => 중복 방지!
user.set_password(password)
# 암호화 위해서 set_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):
AMBITIOUS_DUST = 'AD'
POPPING_DUST = 'PD'
TINY_DUST = 'TD'
EXCITING_DUST = 'ED'
DUST_CHOICES = [
(AMBITIOUS_DUST, '야망있는 먼지'),
(POPPING_DUST, '통통튀는 먼지'),
(TINY_DUST, '조구만 먼지'),
(EXCITING_DUST, '신나는 먼지'),
]
email = models.EmailField(unique=True)
# 한 이메일로 계정 한 개만 생성 가능하게?
nickname = models.CharField(max_length=20, blank=True, null=True)
dust_type = models.CharField(max_length=10, choices=DUST_CHOICES, blank=True, null=True)
big_star = models.PositiveIntegerField(default=0, blank=True, null=True)
small_star = models.PositiveIntegerField(default=0, blank=True, null=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(max_length=30, auto_now_add=True)
objects = UserManager()
# 헬퍼 클래스 지정하기
USERNAME_FIELD = 'email' #email을 username field로 사용
REQUIRED_FIELDS = [] #required_fields를 비워서 username을 required_fields에서 제외
#django는 기본적으로 username을 사용. 이메일을 username으로 사용하기!
class Meta:
db_table: 'User'
def __str__(self):
if self.nickname is None: #생성된 superuser는 nickname을 갖지 않아, admin에서 에러 방지하는 임시 코드
return '슈퍼유저먼지'
return self.nickname
User 모델과 One-To-One 관계를 갖는 Profile 모델,
AbstractUser를 상속하는 User 모델,
그리고 이 최종 모델까지, 총 3개를 왔다갔다하는 삽질을 하느라 불필요한 import가 많아졌다..
User 모델이 최종 확정되면 정리할 예정..!!