email을 username 대신 인증 수단으로 사용한다.
이를 위해 BaseUser에서 필요한 기능들을 가져온다.
usermanager
객체가 생성되거나 검색되는 방식을 지정하는 클래스
객체 생성 방식을 변경할 때마다 사용자 지정 관리자를 정의하고 메서드가 작동하는 방식을 변경해야 하므로 중요하게 이용될 수 있다.
from datetime import timezone
from django.db import models
from helpers.models import TrackingModel
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.contrib.auth.models import PermissionsMixin,AbstractBaseUser,UserManager
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
# Create your models here.
# add new prooperites access_token, is_email_verified
# Use email and password instead of username/password
class MyUserManager(UserManager) :
use_in_migrations = True
def _create_user(self, username, email, password, **extra_fields):
"""
Create and save a user with the given username, email, and password.
"""
# username 미입력시
if not username:
raise ValueError('The given username must be set')
#email 미입력시
if not email:
raise ValueError('The given email must be set')
# email 유효성 검사
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(username, email, password, **extra_fields)
def create_superuser(self, username, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(username, email, password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin,TrackingModel) :
"""
An abstract base class implementing a fully featured User model with
admin-compliant permissions.
Username and password are required. Other fields are optional.
"""
# username에 대한 유효성 검사
username_validator = UnicodeUsernameValidator()
# username은 char field
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
email = models.EmailField(_('email address'), blank=False,unique=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
email_verified = models.BooleanField(
_('email_verified'),
default=False,
help_text=_(
'Designates whether this user email is verified '
),
)
objects = MyUserManager()
EMAIL_FIELD = 'email'
#username 필드를 email로 선언하면 email을 기본 로그인 수단으로 이용할 수 있다.!!
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
@property
def token(self) :
return ''
pip install coverage
coverage run manage.py test && coverage report && coverage html
from rest_framework.test import APITestCase
from authentication.models import User
class TestModel(APITestCase) :
def test_creates_user(self) :
user=User.objects.create_user('test','test@gmail.com','password123!@#')
self.assertIsInstance(user,User)
self.assertFalse(user.is_staff)
self.assertEqual(user.email,'test@gmail.com')
def test_creates_super_user(self) :
user=User.objects.create_superuser('test','test@gmail.com','password123!@#')
self.assertIsInstance(user,User)
self.assertTrue(user.is_staff)
self.assertEqual(user.email,'test@gmail.com')
from rest_framework.test import APITestCase
from authentication.models import User
class TestModel(APITestCase) :
# 기본 유저 생성
def test_creates_user(self) :
# 기본 유저 생성
user=User.objects.create_user('test','test@gmail.com','password123!@#')
self.assertIsInstance(user,User)
# 기본 user가 staff가 아닌가?
self.assertFalse(user.is_staff)
# 생성된 user의 email과 생성시 입력한 email이 일치하는가
self.assertEqual(user.email,'test@gmail.com')
# 슈퍼 유저 생성
def test_creates_super_user(self) :
# 슈퍼 유저 생성
user=User.objects.create_superuser('test','test@gmail.com','password123!@#')
# 생성된 이메일이 User model의 instance인가.
self.assertIsInstance(user,User)
# 생성된 객체가 staff가 맞는가 ?
self.assertTrue(user.is_staff)
# 생성된 user의 email과 생성시 입력한 email이 일치하는가
self.assertEqual(user.email,'test@gmail.com')
#username 미입력 오류 테스트
def test_raises_error_when_no_username_is_supplied(self) :
self.assertRaises(ValueError,User.objects.create_superuser, username="",email='test@gmail.com',password='password123!@#')
self.assertRaisesMessage(ValueError,'The given username must be set')
def test_raises_error_with_message_when_no_username_is_supplied(self) :
with self.assertRaisesMessage(ValueError,'The given username must be set') :
User.objects.create_superuser(username='',email='test@gmail.com',password='password123!@#')
def test_raises_error_when_no_email_is_supplied(self) :
self.assertRaises(ValueError,User.objects.create_superuser, username="test",email='',password='password123!@#')
def test_raises_error_with_message_when_no_email_is_supplied(self) :
with self.assertRaisesMessage(ValueError,'The given email must be set') :
User.objects.create_superuser(username='test',email='',password='password123!@#')
def test_creates_super_user_with_staff_status(self) :
with self.assertRaisesMessage(ValueError,'Superuser must have is_staff=True.') :
User.objects.create_superuser(username='test',email='test@naver.com',password='password123!@#',is_staff=False)
def test_creates_super_user_with_super_user_status(self) :
with self.assertRaisesMessage(ValueError,'Superuser must have is_superuser=True.') :
User.objects.create_superuser(username='test',email='test@naver.com',password='password123!@#',is_superuser=False)
authentication\admin.py 3 0 100%
authentication\apps.py 3 3 0%
authentication\models.py 47 1 98%
authentication\views.py 1 1 0%
todos\admin.py 1 0 100%
todos\apps.py 3 3 0%
todos\models.py 1 0 100%
todos\tests.py 1 0 100%
todos\views.py 1 1 0%