#1. User Model 작성하기

toto9602·2021년 11월 21일
1

RN + DRF 프로젝트

목록 보기
4/5

글에 앞서, User 모델 작성에 많은 도움을 준 포스팅 두 개를 먼저 소개하고자 한다!

Django login 유저 확장 방법


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 등...??)


해당 방법에 정착한 이유는 크게 2가지인데,

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 모델이 최종 확정되면 정리할 예정..!!

profile
주니어 백엔드 개발자입니다! 조용한 시간에 읽고 쓰는 것을 좋아합니다 :)

0개의 댓글