"회원관리 2. 커스텀유저(AbstractUser 이용)"의 두 판 사이의 차이
(→모델 작성) |
잔글 (Sam님이 회원관리 2. 커스텀유저 문서를 회원관리 2. 커스텀유저(AbstractUser 이용) 문서로 이동했습니다) |
(차이 없음)
|
2021년 9월 23일 (목) 09:37 판
1 개요
기본적으로 제공되는 유저모델은 제한적이다. 학교에서 운영한다면 학번 등의 정보를 저정해야 하는데, 이처럼 제공하지 않는 기능들을 확장하는 과정이 필요하다.
장고에서 기본적으로 제공해주는 항목을 넘어 개별항목을 지정하는 등의 작업을 하기 위해 처음부터 커스텀유저를 사용하길 권장한다.
방법 | 설명 |
---|---|
Proxy. 대리모델 사용하기. | 장고 내에서가 아닌, 다른 사이트에서 사용되는 유저권한 등을 위임받아와 사용한다. |
Profile. 프로필 사용. | 단순히 프로필에 들어갈 내용을 더 확장하려면 새로운 모델을 만들어 OneToOneField를 사용해 프로필을 늘리면 되는데, 굳이 어려운 커스텀모델을 다시 짜는 이유는 아이디 대신 이메일로 로그인한다든가, 권한을 부여하는 등 다양한 편의기능을 구현하기 위함이다. 게다가 이런 방식으로 만들면 또 다른 DB를 불러와야 한다는 단점도 있다.
굳이 편의기능이 필요하지 않다면 Admin창에 InlineModelAdmin 등으로 모델을 연결하여 관리하면 된다. 그러나, 공부를 위해, 이후 추가될 기능들을 위해 미리 익혀두면 좋으리라. |
AbstractBaseUser. | 완전 새로운 모델을 사용하기 위함.(모델을 상속해서 만들어진다.) DB에 큰 영향을 미치기 때문에 프로젝트 시작 전에 구성되어야 한다.
id 대신 이메일 로그인을 구현한다든가 특수한 기능이 필요할 때 사용한다.(장고에서 제공하는 권한이 프로젝트와 맞지 않은 경우) 기본 속성으로 id(기본키), password, last_login 필드만 들어있다. |
AbstractUser. | 존재하는 기존 필드들을 사용한다.(위 모델의 확장판이라 보면 된다.) 이 모델을 사용한다 해서 이메일 로그인을 구현하지 못하는 것은 아니다. 마찬가지로 프로젝트 시작 전에 구성되어야 한다.
사용하기 위해선 settings.py의 설정이 필요하다. 기본 속성으로 id(기본키), password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined 필드가 들어있다. |
일반적으로 본격적인 프로젝트를 시작하기 전에 만들기가 권장된다. 프로젝트 도중에 모델을 바꾸는 것은 DB의 왜래키나 다대다 관계에 영향을 미치는데, 이를 다시 고치는 일은 꽤 어려운 일이기 때문이다.(중간에 커스텀모델을 추가하는 경우엔 DB자체를 지우고, 다시 구성한다.) 장고의 의존성 특성 때문에 최초의 DB에 생성되어 포함되어야 한다.
1.1 사용하는 것은 AbstractBaseUser
AbstractUser는 크게 변경하거나 확장하는 내용이 많지 않다.(그냥 Profile 방식을 사용해도 되지 않을까 싶을 정도로..) 하여, 여기에선 조금 어렵지만, 더 자유로운 BaseUser에 대해 다뤄보고자 한다.
2 사전작업
2.1 settings.py에 만들 모델 추가
보통은 앱이름은 account, 모델이름은 MyUser, Account, CustomUser, User 따위가 된다.
AUTH_USER_MODEL = '앱이름.모델이름' # 관리유저로 사용할 모델을 설정한다.
3 모델 작성
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class User(AbstractBaseUser):
# 계정관련
identifier = models.CharField(max_length=20, unique=True) # 로그인 할 때 사용할 식별자.
email = models.EmailField(max_length=60)
# 유저정보 관련
nickname = models.CharField(max_length=10, unique=True) # 드러날 식별자. 변경 가능하지만, 유일하다.
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' # 어떤 것을 로그인 때의 식별자로 사용할 것인가.
def __str__(self):
return self.nickname
def has_perm(self, perm, obj=None): # 특정 권한을 가졌는지 여부를 파악하는 메서드. 제대로 작성하기 위해선 기존의 has_perm 메서드를 뜯어볼 필요가 있겠다.
return self.is_admin
def has_module_perms(self, app_label):
return True
def email_send(self, subject, message, from_email=None, **kwargs): # 이메일 발송을 위해.
pass
objects = AccountManager() # 회원가입을 다룰 클래스(이후 작성)
username와 같이 장고에서 기본적으로 구현해 주는 필드에 적용하려면, AbstractBaseUser을 상속한 다음 USERNAME_FIELD 등 특수한 변수에 등록해야 한다.
3.1 DB에 반영
다른 앱의 모델에서 유저를 참조하는 경우, 참조테이블로 User가 들어가 있는데, 이 때문에 'auth.User', which has been swapped out. 라는 에러가 뜬다.
이것과 from django.contrib.auth.models import User를 지우고, from django.conf import settings 후에
User 대신 settings.AUTH_USER_MODEL를 넣어주면 된다.
3.2 관리자 계정 작성
manage.py createsuperuser 를 실행해 관리자계정을 만들려 하면
AttributeError: 'Manager' object has no attribute 'get_by_natural_key' 에러가 뜬다. 이는 메니저가 구현되어있지 않기 때문. 다음과 같이 유저메니저를 만들어주기만 하자.
class AccountManager(BaseUserManager):
pass
그리고 위 커스텀유저모델 안에 objects = AccountManager() 변수를 추가해준다.(AccountManager를 참조하기 위해 AccountManager는 커스텀유저 위에 작성해주어야 한다.)
다시 시도해보면 이 에러가 뜬다. object has no attribute 'create_superuser'
내용이 안채워졌기 때문인데, 내용을 채워가 보자.
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
사람마다 짜는 방식이 달라서, 그리고 일일이 주석을 달아두지 않기 때문에 처음 하는 사람들은 해석하는 데 적잖이 애먹는다.
3.3 관리자 화면에 등록
admin.py를 작성한다.
from django.contrib import admin
from .models import User # 직접 등록한 모델
#from django.contrib.auth import get_user_model은 안되나?? 확인해보자.
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('identifier', 'email','nickname', 'joined_at', 'last_login_at')
list_display_links = ('identifier', 'email')
exclude = ('password',) # 사용자 상세 정보에서 비밀번호 필드를 노출하지 않음
def joined_at(self, obj):
return obj.date_joined.strftime("%Y-%m-%d")
def last_login_at(self, obj):
if not obj.last_login:
return ''
return obj.last_login.strftime("%Y-%m-%d %H:%M")
joined_at.admin_order_field = '-date_joined' # 가장 최근에 가입한 사람부터 리스팅
joined_at.short_description = '가입일'
last_login_at.admin_order_field = 'last_login_at'
last_login_at.short_description = '최근로그인'
그럼 이제 이 모델로 계정관리가 가능해진다.
4 폼 작성
기본 폼은 password 따위를 암호화하지 않고 그대로 저장한다. 폼을 밑바닥부터 만들려면 알아야 할 것도 많은데, UserCreationForm을 이용해 폼을 다뤄보자.
changeform은 굳이 사용하지 않아도 된다. 회원관리 참고..
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth import get_user_model # 직접 불러올 수도 있지만, settings 파일에서 설정된 모델을 자동으로 불러오는 편이 수정에 유용하지.
class UserCreateForm(UserCreationForm):
class Meta:
model = get_user_model # 설정된 커스텀모델
fields = ["identifier","email"] # 패스워드는 자동추가.
class UserUpdateForm(UserChangeForm):
class Meta:
model = get_user_model
fields = ["username", "password1", "password2", "email"]
굳이 많은 기능을 추가하지 않는다면 뷰에서 바로 장고 제공 폼을 사용하기도 한다.
password부분은 UserCreationForm에 정의된 것들이라 오버라이드 해줘야 한다.
비밀번호 조건은 settings.py의 AUTH_PASSWORD_VALIDATORS 안에 있는 조건들을 거쳐야 한다.
5 모델
커스텀유저를 외래키로 사용하고 싶다면
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
위와 같은 형태로 사용하면 된다.
[의문. 글쓰기 뷰에서 저자를 불러올 때에도 settings.AUTH_USER_MODEL이면 될까/?]