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"> |