[장고] 커스텀 사용자 모델 만들기

소요 시간: 5분

사용자 인증 시스템은 장고의 핵심 기능 중 하나입니다. 기본 기능만으로도 사이트를 운영하는 데 충분하지만, 때로는 사용자 프로필 정보나 추가 인증 정보를 저장해야 할 필요가 있습니다. 이러한 요구를 충족시키려면 장고의 기본 사용자 모델을 확장해야 합니다.

이 글에서는 장고의 기본 사용자 모델을 커스터마이징하는 방법을 다룹니다. 커스텀 사용자 모델의 필요성을 이해하고, 실제 프로젝트에서 적용할 수 있는 구체적인 방법들을 소개합니다. 이를 통해 더 안전하고 효율적인 웹 애플리케이션을 개발할 수 있습니다.


커스텀 사용자 모델의 필요성

모든 웹 애플리케이션이 동일한 사용자 데이터를 요구하지 않기 때문에, 커스텀 사용자 모델이 필요합니다. 예를 들어, 사용자의 생년월일, 주소, 프로필 사진 등의 추가 정보를 저장하려면 기본 사용자 모델로는 부족합니다.


장고의 기본 사용자 모델

장고는 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 메서드

이 메서드는 일반 사용자를 생성합니다.

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 메서드

이 메서드는 슈퍼유저를 생성합니다.

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을 상속받아 필요한 필드와 메서드를 추가합니다.

필드
메타데이터
메서드

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의 기본 사용자 모델을 대신하여 이메일을 기반으로 사용자 관리를 쉽게 할 수 있도록 돕습니다. 주요 구성 요소는 다음과 같습니다:

이렇게 설정하면 이메일을 기반으로 사용자 인증을 수행할 수 있으며, 사용자 관리 로직을 커스터마이징할 수 있습니다.


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을 상속받아 사용자 인증과 퍼미션 관리를 모두 포함하도록 했으며, 관리자 페이지에서 사용자와 관련된 퍼미션을 쉽게 관리할 수 있도록 설정했습니다. 이 과정을 통해 더 강력하고 유연한 사용자 인증 시스템을 구축할 수 있을 것입니다.

장고 리스트