from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from apps.core.models import TimeStampedModel
from apps.user.managers import UserManager
class User(AbstractBaseUser, PermissionsMixin, TimeStampedModel):
email = models.EmailField(
max_length=255,
unique=True,
)
nickname = models.CharField(
max_length=50,
)
profile_img = models.CharField(max_length=255, null=True, blank=True)
bio = models.CharField(max_length=150, null=True, blank=True)
# 활성화 여부: True면 로그인 가능, False면 계정 정지 등의 상태(기본값은 True)
is_active = models.BooleanField(default=True)
# 관리자 사이트 접속 권한 여부: True면 admin 페이지 접속 가능
is_staff = models.BooleanField(default=False)
objects = UserManager()
# 로그인 시 식별자로 사용할 필드를 지정합니다. 여기서는 'email'을 아이디로 씁니다.
USERNAME_FIELD = "email" # 로그인은 이메일로
# createsuperuser 커맨드로 관리자 계정을 만들 때, 이메일/비번 외에 추가로 입력받을 필드입니다.
REQUIRED_FIELDS = ["nickname"] # createsuperuser 할 때 물어볼 필드
class Meta:
db_table = "users"
verbose_name = "사용자"
verbose_name_plural = "사용자 목록"
def __str__(self) -> str:
return f"{self.nickname} ({self.email})"
Django의 Manager는 데이터베이스 질의(Query) 작업이 인터페이스되는 통로
User.objects.create_user()와 같은 메서드를 호출할 때 실제 내부 로직을 담당하는 '유저 생성 대리인'BaseUserManager 상속AbstractBaseUser 모델 내부에서 objects = UserManager() 와 같이 연결되어 사용normalize_emailBaseUserManager에서 제공하는 메서드test@EXAMPLE.COM 을 test@example.com 으로 변환하여 동일성을 보장set_passwordPBKDF2 알고리즘 등으로 암호화(Hashing)def create_user(self, email, nickname, password=None, **extra_fields):
if not email:
raise ValueError("이메일은 필수 입력값입니다.")
# 1. 이메일 정규화 (Domain 부분을 소문자로 변환)
email = self.normalize_email(email)
# 2. 유저 객체 생성 (self.model은 이 Manager가 연결된 User 모델을 의미함)
user = self.model(email=email, nickname=nickname, **extra_fields)
# 3. 비밀번호 설정
if password:
user.set_password(password) # 해시(Hash)화하여 저장
else:
# 소셜 로그인 등 비밀번호가 없는 경우 로그인을 직접 못 하도록 설정
user.set_unusable_password()
# 4. 데이터베이스 저장
user.save(using=self._db)
return user
def create_superuser(self, email, nickname, password, **extra_fields):
# 권한 관련 기본값 설정
extra_fields.setdefault("is_staff", True) # 관리자 페이지 접속 권한
extra_fields.setdefault("is_superuser", True) # 모든 권한 허용
extra_fields.setdefault("is_active", True) # 계정 활성화 상태
# 권한 검증 로직 (필수 사항)
if extra_fields.get("is_staff") is not True:
raise ValueError("Superuser must have is_staff=True.")
if extra_fields.get("is_superuser") is not True:
raise ValueError("Superuser must have is_superuser=True.")
# 위에서 정의한 create_user를 재활용하여 실제 유저 생성
return self.create_user(email, nickname, password, **extra_fields)
email 을 아이디로 사용
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
# 기본 필드(username, email 등)는 이미 존재함
phone_number = models.CharField(max_length=15, blank=True) # 추가 필드만 정의
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
# 앞에서 만든 UserManager를 가져옵니다.
# from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True) # 이메일을 식별자로 사용
nickname = models.CharField(max_length=20)
is_staff = models.BooleanField(default=False)
# 이 모델에서 아이디로 사용할 필드 지정
USERNAME_FIELD = 'email'
# createsuperuser 실행 시 추가로 물어볼 필드
REQUIRED_FIELDS = ['nickname']
# 위에서 만든 UserManager 연결
objects = UserManager()
def __str__(self):
return self.email
PermissionsMixinAbstractBaseUser 가 담당PermissionsMixin 이 담당AbstractBaseUser 는 매우 가볍기 때문에 권한(Groups, Permissions)과 관련된 필드나 메서드가 전혀 없음Mixin을 상속받아야 함is_superusergroupsuser_permissionshas_perm(perm)has_module_perms(app_label)get_all_permissions()from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, verbose_name="이메일 주소")
nickname = models.CharField(max_length=20, verbose_name="닉네임")
# 관리자 페이지 접근 여부 (PermissionsMixin과 별개로 관리자가 되기 위한 필수 필드)
is_staff = models.BooleanField(default=False)
# 계정 활성화 여부
is_active = models.BooleanField(default=True)
# 1. 헬퍼 클래스 연결
objects = UserManager()
# 2. 로그인에 사용할 필드 지정
USERNAME_FIELD = 'email'
# 3. 필수 입력 필드 (createsuperuser 실행 시 물어볼 항목)
REQUIRED_FIELDS = ['nickname']
def __str__(self):
return self.email
class Meta:
verbose_name = "사용자"
verbose_name_plural = "사용자들"
has_perm 같은 메서드를 호출하는데, 이 메서드가 유저 모델에 없기 때문@permission_required 같은 편리한 기능을 쓸 수 없음