[장고] 커스텀 사용자 모델 만들기
사용자 인증 시스템은 장고의 핵심 기능 중 하나입니다. 기본 기능만으로도 사이트를 운영하는 데 충분하지만, 때로는 사용자 프로필 정보나 추가 인증 정보를 저장해야 할 필요가 있습니다. 이러한 요구를 충족시키려면 장고의 기본 사용자 모델을 확장해야 합니다.
이 글에서는 장고의 기본 사용자 모델을 커스터마이징하는 방법을 다룹니다. 커스텀 사용자 모델의 필요성을 이해하고, 실제 프로젝트에서 적용할 수 있는 구체적인 방법들을 소개합니다. 이를 통해 더 안전하고 효율적인 웹 애플리케이션을 개발할 수 있습니다.
커스텀 사용자 모델의 필요성
모든 웹 애플리케이션이 동일한 사용자 데이터를 요구하지 않기 때문에, 커스텀 사용자 모델이 필요합니다. 예를 들어, 사용자의 생년월일, 주소, 프로필 사진 등의 추가 정보를 저장하려면 기본 사용자 모델로는 부족합니다.
장고의 기본 사용자 모델
장고는 AbstractBaseUser와 AbstractUser라는 두 가지 기본 사용자 모델을 제공합니다. AbstractBaseUser는 사용자 모델의 핵심 기능만을 제공하며, AbstractUser는 기본 사용자 모델을 확장한 형태로 더 많은 기능을 제공합니다.
커스텀 사용자 모델 구축하기
1. 커스텀 사용자 모델 설계
먼저, 커스텀 사용자 모델을 정의합니다. 이 모델은 AbstractBaseUser와 PermissionsMixin을 상속받아 사용자 인증과 퍼미션 기능을 모두 포함하도록 합니다.
예를 들어, 사용자의 휴대폰 번호와 프로필 사진을 저장하는 모델을 설계해보겠습니다.
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('The Email field must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=15, blank=True, null=True)
profile_picture = models.ImageField(upload_to='profile_pics/', blank=True, null=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
위의 코드에서는 이메일을 사용자 이름으로 사용하고, 휴대폰 번호와 프로필 사진을 저장하는 필드를 추가했습니다.
코드를 자세히 알아보겠습니다.
CustomUserManager 클래스
CustomUserManager는 사용자 생성 로직을 담당하는 클래스입니다. BaseUserManager를 상속받아 사용자와 슈퍼유저를 생성하는 메서드를 정의합니다.
create_user 메서드
이 메서드는 일반 사용자를 생성합니다.
- 이메일 유효성 검사: 이메일이 없으면 ValueError를 발생시킵니다.
- 이메일 정규화: normalize_email 메서드를 사용하여 이메일을 표준 형식으로 변환합니다.
- 사용자 인스턴스 생성: self.model을 사용하여 새로운 사용자 인스턴스를 생성합니다.
- 비밀번호 설정: set_password 메서드를 사용하여 비밀번호를 해시화합니다.
- 사용자 저장: user.save(using=self._db)를 통해 데이터베이스에 사용자를 저장합니다.
- 반환: 최종적으로 생성된 사용자 인스턴스를 반환합니다.
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('The Email field must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
create_superuser 메서드
이 메서드는 슈퍼유저를 생성합니다.
- 기본 필드 설정: is_staff와 is_superuser 필드를 기본값으로 True로 설정합니다.
- 슈퍼유저 생성: create_user 메서드를 호출하여 슈퍼유저를 생성합니다.
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self.create_user(email, password, **extra_fields)
CustomUser 클래스
CustomUser는 사용자 모델을 정의합니다. AbstractBaseUser와 PermissionsMixin을 상속받아 필요한 필드와 메서드를 추가합니다.
필드
- email: 유일한 이메일 필드입니다.
- phone_number: 전화번호를 저장하는 필드입니다. 빈 값과 null 값을 허용합니다.
- profile_picture: 프로필 사진을 저장하는 이미지 필드입니다. 빈 값과 null 값을 허용합니다.
- is_active: 사용자가 활성 상태인지 여부를 나타내는 불리언 필드입니다.
- is_staff: 사용자가 스태프 권한을 가지고 있는지 여부를 나타내는 불리언 필드입니다.
메타데이터
- objects: 사용자 생성과 관리를 담당하는 매니저 클래스(CustomUserManager)를 지정합니다.
- USERNAME_FIELD: 로그인에 사용할 필드를 email로 지정합니다.
- REQUIRED_FIELDS: createsuperuser 명령을 실행할 때 요구되는 추가 필드 리스트입니다. 여기서는 빈 리스트로 설정되어 있습니다.
메서드
- __str__: 사용자 객체를 문자열로 표현할 때 이메일을 반환합니다.
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=15, blank=True, null=True)
profile_picture = models.ImageField(upload_to='profile_pics/', blank=True, null=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
PermissionsMixin
PermissionsMixin은 Django의 내장 믹스인 클래스로, CustomUser 모델에 권한 및 그룹 관련 기능을 추가합니다. 이를 통해 사용자 모델에 권한 및 그룹 기능을 쉽게 통합할 수 있습니다.
PermissiosMixin에 대해 더 자세히 알아보기
objects = CustomUserManager()
objects는 CustomUser 모델에서 사용할 매니저를 지정합니다. 여기서는 CustomUserManager를 사용하여 사용자 생성과 관리를 담당하도록 합니다. 매니저 클래스는 데이터베이스 쿼리 및 객체 생성과 관련된 메서드를 정의하는 데 사용됩니다.
USERNAME_FIELD = 'email'
USERNAME_FIELD는 Django의 인증 시스템에서 사용자가 로그인할 때 사용할 필드를 지정합니다. 기본 Django 사용자 모델에서는 username 필드를 사용하지만, 이 커스텀 사용자 모델에서는 email을 로그인 ID로 사용하도록 지정합니다.
REQUIRED_FIELDS = []
REQUIRED_FIELDS는 createsuperuser 명령을 실행할 때 필수적으로 입력해야 하는 추가 필드 목록을 지정합니다. 기본 사용자 모델에서는 username 필드 외에 email 등이 포함되지만, 여기서는 이미 USERNAME_FIELD에 email을 사용하므로 추가로 요구되는 필드가 없습니다. 따라서 빈 리스트로 설정되어 있습니다.
요약
이 코드는 Django의 기본 사용자 모델을 대신하여 이메일을 기반으로 사용자 관리를 쉽게 할 수 있도록 돕습니다. 주요 구성 요소는 다음과 같습니다:
- CustomUserManager: 사용자와 슈퍼유저를 생성하는 메서드를 포함한 사용자 관리 클래스입니다.
- CustomUser: 이메일을 기본 로그인 필드로 사용하는 사용자 모델입니다.
- PermissionsMixin: 사용자 모델에 권한 및 그룹 관리 기능을 추가합니다.
- objects = CustomUserManager(): 사용자 모델의 매니저로 CustomUserManager를 사용하여 사용자 생성 및 관리 기능을 제공합니다.
- USERNAME_FIELD = 'email': 사용자의 로그인 ID로 이메일을 사용하도록 지정합니다.
- REQUIRED_FIELDS = []: createsuperuser 명령에서 추가로 요구되는 필드를 지정합니다. 여기서는 빈 리스트로 설정하여 추가 요구 필드가 없음을 나타냅니다.
이렇게 설정하면 이메일을 기반으로 사용자 인증을 수행할 수 있으며, 사용자 관리 로직을 커스터마이징할 수 있습니다.
2. 설정 파일 수정
장고 설정 파일(settings.py)에서 기본 사용자 모델을 커스텀 사용자 모델로 변경해야 합니다. 이를 위해 다음과 같이 설정합니다.
AUTH_USER_MODEL = 'your_app.CustomUser'
3. 데이터베이스 마이그레이션
모델을 변경한 후에는 데이터베이스 마이그레이션을 수행합니다.
python manage.py makemigrations
python manage.py migrate
4. 관리자 페이지 설정
커스텀 사용자 모델을 관리자 페이지에서 관리하려면 관리자 페이지 설정을 추가해야 합니다. 이를 위해 admin.py 파일을 다음과 같이 수정합니다.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ('email', 'is_staff', 'is_active')
list_filter = ('is_staff', 'is_active')
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active', 'is_superuser', 'groups', 'user_permissions')}),
('Personal', {'fields': ('phone_number', 'profile_picture')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(CustomUser, CustomUserAdmin)
5. 퍼미션 및 그룹 관리
퍼미션과 그룹을 관리하기 위해 관리자 페이지에서 그룹을 생성하고 필요한 퍼미션을 할당할 수 있습니다. 사용자는 해당 그룹에 추가되어 그룹의 퍼미션을 상속받을 수 있습니다.
퍼미션 확인 및 사용
뷰나 템플릿에서 퍼미션을 확인하고 사용하는 방법은 다음과 같습니다.
if request.user.has_perm('app_name.add_modelname'):
# 사용자에게 객체를 추가할 권한이 있음
pass
else:
# 권한이 없음
pass
뷰에서 @permission_required 데코레이터를 사용하여 특정 뷰에 퍼미션을 요구할 수 있습니다.
from django.contrib.auth.decorators import permission_required
@permission_required('app_name.change_modelname')
def my_view(request):
# 사용자가 객체를 수정할 권한이 있는 경우에만 실행
pass
커스텀 사용자 모델 확장하기
추가 필드와 메서드
프로젝트의 요구사항에 따라 커스텀 사용자 모델에 추가 필드와 메서드를 정의할 수 있습니다. 예를 들어, 사용자의 생일을 저장하고, 연령을 계산하는 메서드를 추가할 수 있습니다.
from django.utils import timezone
class CustomUser(AbstractBaseUser):
# 기존 필드들...
birth_date = models.DateField(null=True, blank=True)
def get_age(self):
if self.birth_date:
return timezone.now().year - self.birth_date.year
return None
시그널을 이용한 추가 기능
장고 시그널을 사용하여 사용자 모델의 특정 이벤트 발생 시 추가 작업을 수행할 수 있습니다. 예를 들어, 사용자가 생성될 때 프로필을 자동으로 생성하는 기능을 추가할 수 있습니다.
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
bio = models.TextField()
@receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=CustomUser)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
결론
이 예제에서는 커스텀 사용자 모델을 생성하고, 퍼미션 관련 기능을 포함하는 방법을 설명했습니다. AbstractBaseUser와 PermissionsMixin을 상속받아 사용자 인증과 퍼미션 관리를 모두 포함하도록 했으며, 관리자 페이지에서 사용자와 관련된 퍼미션을 쉽게 관리할 수 있도록 설정했습니다. 이 과정을 통해 더 강력하고 유연한 사용자 인증 시스템을 구축할 수 있을 것입니다.