바뀜

1,100 바이트 제거됨 ,  2021년 11월 2일 (화) 10:00
31번째 줄: 31번째 줄:  
AbstractUser는 크게 변경하거나 확장하는 내용이 많지 않다.(그냥 Profile 방식을 사용해도 되지 않을까 싶을 정도로..) 하여, 여기에선 조금 어렵지만, 더 자유로운 BaseUser에 대해 다뤄보고자 한다.
 
AbstractUser는 크게 변경하거나 확장하는 내용이 많지 않다.(그냥 Profile 방식을 사용해도 되지 않을까 싶을 정도로..) 하여, 여기에선 조금 어렵지만, 더 자유로운 BaseUser에 대해 다뤄보고자 한다.
 
==사전작업==
 
==사전작업==
 +
어떤 앱의 어떤 모델을 기본 유저로 사용할지 생각하고 진행한다.
 +
 
===settings.py에 만들 모델 추가===
 
===settings.py에 만들 모델 추가===
 
보통은 앱이름은 account, 모델이름은 MyUser, Account, CustomUser, User 따위가 된다.<syntaxhighlight lang="python">
 
보통은 앱이름은 account, 모델이름은 MyUser, Account, CustomUser, User 따위가 된다.<syntaxhighlight lang="python">
37번째 줄: 39번째 줄:  
</syntaxhighlight>
 
</syntaxhighlight>
 
==모델 작성==
 
==모델 작성==
<syntaxhighlight lang="python">
+
필수적으로 2개의 모델을 작성해주어야 한다. BaseUserManager를 상속받은 모델과 AbstractBaseUser를 상속받은 모델.
 +
 
 +
사람마다 짜는 방식이 달라서, 그리고 일일이 주석을 달아두지 않기 때문에 처음 하는 사람들은 해석하는 데 적잖이 애먹는다.
 +
{| class="wikitable"
 +
!과정
 +
!설명
 +
!코드
 +
|-
 +
|모듈 임포트
 +
|모델과 유저모델을 불러온다.
 +
|<syntaxhighlight lang="python">
 
from django.db import models
 
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
+
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)
 +
</syntaxhighlight>
 +
|-
 +
|BaseUserManager
 +
|유저를 생성할 때 사용하는 헬퍼.
 +
AbstractBaseUser가 참고하니, 그보다 위에 작성되어야 한다.
       +
인수로 받는 email 등을 다른 것으로 바꿀 수 있다.
 +
 +
 +
다음 코드는 email 대신 identifier를 넣는 등 메뉴얼에서 제공하는 코드를 바꾸어,
 +
 +
최대한 단순화하여 아이디와 패스워드만 받는 코드이다.
 +
|<syntaxhighlight lang="python">
 +
class UserManager(BaseUserManager):
 +
    def create_user(self, identifier, password=None):
 +
        user = self.model(              # 이 안에 유저 정보에 필요한 필드를 넣으면 된다.
 +
            identifier = identifier    # 왼쪽이 필드, 오른쪽이 넣을 값.
 +
        )
 +
        user.set_password(password)
 +
        user.save(using=self._db)
 +
        return user
 +
 +
    def create_superuser(self, identifier, password):
 +
        user = self.create_user(
 +
            identifier,
 +
            password=password,
 +
        )
 +
        user.is_admin = True
 +
        user.save(using=self._db)
 +
        return user
 +
</syntaxhighlight>
 +
|-
 +
|AbstractBaseUser
 +
|커스텀 유저 모델. 다음 코드도 최대한 단순화 한 것이지만... 필수 필드를 갖고 있다.
 +
{| class="wikitable"
 +
!필수필드
 +
!설명
 +
|-
 +
|is_active
 +
|계정을 활성화 하는가.
 +
|-
 +
|is_admin
 +
|관리자 계정인가.
 +
|}
 +
기타 필드
 +
{| class="wikitable"
 +
!필수필드
 +
!설명
 +
|-
 +
|is_staff
 +
|어드민에 접속할 권한.
 +
|-
 +
|is_superuser
 +
|그냥 모든 권한.
 +
|}
 +
|<syntaxhighlight lang="python">
 
class User(AbstractBaseUser):
 
class User(AbstractBaseUser):
    # 계정관련
+
     identifier = models.CharField(max_length=20, unique=True)
     identifier = models.CharField(max_length=20, unique=True) # 로그인 할 때 사용할 식별자.
+
     is_active = models.BooleanField(default=True)
    email = models.EmailField(max_length=60)
+
     is_admin = models.BooleanField(default=False)
    # 유저정보 관련
+
 
    nickname = models.CharField(max_length=10, unique=True)  # 드러날 식별자. 변경 가능하지만, 유일하다.
+
     objects = UserManager()  # 회원가입을 다룰 클래스를 지정한다.
    date_joined = models.DateTimeField(auto_now_add=True)
  −
    last_login = models.DateTimeField(auto_now=True)  # 마지막 로그인 시간을 저장하기.
  −
    # 유저권한 관련
  −
     is_active = models.BooleanField(default=False) # 장고 필수필드
  −
     is_staff = models.BooleanField(default=False) # 어드민에 접속할 권한.
  −
     is_admin = models.BooleanField(default=False)  # 장고 필수필드
  −
    is_superuser = models.BooleanField(default=False)  # 딱히 지정하지 않고 모든 권한을 줄 때
     −
     REQUIRED_FIELDS = ['email', ]  # 입력할 때 필수입력 필드 지정.
+
     USERNAME_FIELD = 'identifier'   # 식별자로 사용할 필드.
     USERNAME_FIELD = 'identifier'  # 어떤 것을 로그인 때의 식별자로 사용할 것인가.
+
     REQUIRED_FIELDS = []            # 회원가입 때 필수 입력필드.
    
     def __str__(self):
 
     def __str__(self):
         return self.nickname
+
         return self.identifier
   −
     def has_perm(self, perm, obj=None): # 특정 권한을 가졌는지 여부를 파악하는 메서드. 제대로 작성하기 위해선 기존의 has_perm 메서드를 뜯어볼 필요가 있겠다.
+
     def has_perm(self, perm, obj=None):
         return self.is_admin
+
        '''권한 소지여부를 판단하기 위한 메서드'''
 +
         return True
    
     def has_module_perms(self, app_label):
 
     def has_module_perms(self, app_label):
 +
        '''앱 라벨을 받아, 해당 앱에 접근 가능한지 파악'''
 
         return True
 
         return True
   −
     def email_send(self, subject, message, from_email=None, **kwargs):  # 이메일 발송을 위해.
+
    @property
        pass
+
     def is_staff(self):
 +
        '''이게 True면 관리자화면에 접근 가능'''
 +
        return self.is_admin
 +
</syntaxhighlight>
 +
|-
 +
|
 +
|
 +
|
 +
|}
   −
    objects = AccountManager()  # 회원가입을 다룰 클래스(이후 작성)
  −
</syntaxhighlight>username와 같이 장고에서 기본적으로 구현해 주는 필드에 적용하려면, AbstractBaseUser을 상속한 다음 USERNAME_FIELD 등 특수한 변수에 등록해야 한다.
   
===DB에 반영===
 
===DB에 반영===
다른 앱의 모델에서 유저를 참조하는 경우, 참조테이블로 User가 들어가 있는데, 이 때문에 'auth.User', which has been swapped out. 라는 에러가 뜬다.
+
이 작업을 처음에 하는 게 아니라, 개발 중에 하는 경우, 다른 앱의 모델에서 유저를 참조하고 있을 때 참조테이블로 User가 들어가 있는데, 이 때문에 'auth.User', which has been swapped out. 라는 에러가 뜬다.
    
이것과 from django.contrib.auth.models import User를 지우고, from django.conf import settings 후에
 
이것과 from django.contrib.auth.models import User를 지우고, from django.conf import settings 후에
    
User 대신 settings.AUTH_USER_MODEL를 넣어주면 된다.
 
User 대신 settings.AUTH_USER_MODEL를 넣어주면 된다.
===관리자 계정 작성===
  −
manage.py createsuperuser 를 실행해 관리자계정을 만들려 하면
  −
  −
AttributeError: 'Manager' object has no attribute 'get_by_natural_key' 에러가 뜬다. 이는 메니저가 구현되어있지 않기 때문. 다음과 같이 유저메니저를 만들어주기만 하자.<syntaxhighlight lang="python">
  −
class AccountManager(BaseUserManager):
  −
    pass
  −
</syntaxhighlight>그리고 위 커스텀유저모델 안에 objects = AccountManager() 변수를 추가해준다.(AccountManager를 참조하기 위해 AccountManager는 커스텀유저 위에 작성해주어야 한다.)
  −
  −
다시 시도해보면 이 에러가 뜬다. object has no attribute 'create_superuser'
  −
  −
내용이 안채워졌기 때문인데, 내용을 채워가 보자.<syntaxhighlight lang="python">
  −
class AccountManager(BaseUserManager):  # 계정을 만드는 데 쓰인다.
  −
    use_in_migrations = True
  −
  −
    def create_user(self, identifier, password, email, **extra_fields):  # 모든 유저를 생성할 때 거치는 함수.
  −
        if not email:
  −
            raise ValueError("email 주소가 있어야 합니다.")
  −
        if not identifier:
  −
            raise ValueError("아이디는 입력하셔야죠;")
  −
        email = self.normalize_email(email)
  −
        user = self.model(email=email, identifier=identifier, **extra_fields)  # 커스텀모델에 각종 인자 저장.
  −
        user.set_password(password)
  −
        user.save(using=self._db)
  −
        return user
  −
  −
    def create_superuser(self, identifier, email, password, **extra_fields):  # 관리자계성 생성. 인수는 필요에 따라.(아래 유저모델에서 설정한 필수입력 필드를 포함해야 한다. 그 필드대로 묻는다.)
  −
        user = self.create_user(
  −
            email=self.normalize_email(email),
  −
            password=password,
  −
            identifier=identifier,  # 이름대신 아이디.
  −
        )
  −
        user.is_active = True
  −
        user.is_admin = True  # 어드민과 슈퍼유저는 뭐가 다른걸까;;?
  −
        user.is_staff = True
  −
        user.is_superuser = True
  −
        user.save(using=self._db)
  −
        return user
  −
</syntaxhighlight>사람마다 짜는 방식이 달라서, 그리고 일일이 주석을 달아두지 않기 때문에 처음 하는 사람들은 해석하는 데 적잖이 애먹는다.
  −
   
===관리자 화면에 등록===
 
===관리자 화면에 등록===
 
admin.py를 작성한다.<syntaxhighlight lang="python">
 
admin.py를 작성한다.<syntaxhighlight lang="python">