Django User Model 확장하기

엄성호·2023년 1월 31일
0

Django

목록 보기
3/3

왜 User Model을 확장해야 하는가?

Django는 풀스택 웹프레임워크로 유저, 인증, 로그인, 쿠키, DB처리 등 다양한 기능이 내장되어 있다.
Django는 User의 이름, 비밀번호, 이메일 등의 정보를 DB에 저장하고 안전한 인증과 로그인을 제공한다.

하지만 User에 전화번호, 주소 등 기타 정보를 저장하고 싶다면 User Model을 수정해야 한다.
Django는 User Model을 수정하는 방법을 여러가지 제공한다.

알아야 하는 것

  1. Django는 ORM(Object Relational Mapping)을 사용한다. DB를 사용할 때 SQL을 작성하지 않고 Model을 작성하면 Django가 처리해준다.
  2. 기본상태의 Django User Model은 DB에 이렇게 저장된다.

User Model을 확장하는 4가지 방법

  1. Proxy Model
    • DB에 영향을 주지 않음
    • Model의 행위(behavior)을 수정할 때 사용
  2. OnetoOneField
    • DB에 영향을 주지만 auth_user에는 영향을 주지 않음
    • 새로운 테이블을 만들고, 외래키로 auth_user를 참조하는 방식
    • 정보를 저장하는 필드를 만들 때 사용
  3. AbstractUser
    • DB에 저장된 테이블을 바꾸기 때문에 최초로 migrate 하기 전에 하는게 좋음
    • 장고 앱을 만들던 도중 이 방법을 적용하려면 수동으로 DB를 조작해야함
    • User에 필요한 것들이 포함되어 있고, 비교적 자유롭게 수정이 가능
  4. AbstractBaseUser
    • AbstractUser와 비슷한 방법
    • User Model을 필드, 권한 등 밑바닥부터 모두 만들고 커스터마이징 할 수 있음

Proxy Model

다음과 같은 방법으로 사용할 수 있다.

/myuser/models.py


from django.contrib.auth.models import User


class MyUser(User):
    class Meta:
        proxy = True

    def Myfunc(self):
        return 'My fullname is ' + self.first_name + self.last_name

장고셸에서 다음과 같이 출력해 볼 수 있다.

$ python manage.py shell

>>> from myuser.models import MyUser
>>> u = MyUser.objects.get(first_name='John')
>>> u.Myfunc()
'My fullname is JohnDoe'

또는 쿼리 출력의 ordering을 바꾸는 데 사용할 수 있다.
Proxy Model은 DB에 영향을 주지 않고, 행위에만 영향을 끼친다.

OnetoOneField

기본 User Model에 전화번호와 생일 필드를 추가하고 싶은 상황을 가정해보자.
다음과 같이 작성할 수 있다.

/myuser/models.py


from django.db import models
from django.contrib.auth.models import User


class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(max_length=100)
    birthday = models.DateField(null=True)

이렇게 작성하면 DB에서 다음과 같이 반영된다.

myuser_employee 테이블을 만들고 추가정보를 저장한후, 외래키를 통해 참조하는 방법이다.
admin페이지에서 전화번호와 생일을 보여주려면 admin.py 파일을 수정해야 한다.
auth_user를 바꾸지 않기 때문에 프로젝트가 완성된 후에도 사용할 수 있다.
다만 이 방법을 사용하면 정보를 불러오는 작업을 할 때 마다 myuser_employee도 같이 불러와야 하므로 작성할 코드가 많아진다.
만약 DRF(Django REST Framework)에서 이 방법을 사용한다면 nested 필드이기 때문에 굉장히 복잡해진다.
여러모로 추천하지 않는 방법이다.

AbstractUser

최초로 migrate 하기 전에 작성해야 한다.
최초의 migrate 이후 변경한다면 마이그레이션을 자동으로 하는 방법은 없고 수동으로 DB를 수정해야 한다.
first_name과 last_name을 삭제하고, 전화번호와 생일 필드를 다음과 같이 추가할 수 있다.

/config/setting.py

AUTH_USER_MODEL = 'myuser.User'
/myuser/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    first_name = None
    last_name = None

    birthday = models.DateField(blank=True, null=True, name="birthday")
    phone = models.CharField(max_length=20, blank=True, name="phone")

이렇게 작성하면 DB에서 다음과 같이 반영된다.

이렇게 작성하면 User를 사용할 때 get_user_model이나 AUTH_USER_MODEL을 사용해야 한다.
django.contrib.auth.get_user_model() 를 사용하면 현재 활성화된 모델을 가져온다.
다대다 관계에서 유저 모델을 외래키로 사용할 때는 AUTH_USER_MODEL 를 사용해야 한다.

AbstractBaseUser

장고에서 모델 클래스의 상속은 다음과 같다.

중요한 내용만 작성하고 나머지는 생략했다. Django의 소스코드에서 간단히 확인할 수 있는 내용이다.
AbstractBaseUser는 기초적인 내용만 작성이 되어 있다.
또한 AbstractBaseUser는 PermissionsMixin과 같이 상속해야 사용할 수 있다.
이 방법을 사용하면 Django에서 유저모델을 사용하는 방식을 많이 변경할 수 있다.

추가로 알게된 내용들

  1. Create_user() 혹은 Create_superuser()를 바꾸고 싶다면?
    • UserManager를 상속받아 작성한 후, AbstractUser에 objects를 변경해 주면 된다.
  2. username+password가 아닌 다른방법으로 로그인 하고 싶다면?
    • 다음과 같이 인증 백엔드 부분을 수정하면 된다.
from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...

참고자료

profile
개발자

0개의 댓글