django login 유저 확장 방법
장고의 auth 기능은 User 객체를 제공한다. 우리는 기본 default로 이 User 객체로 여러 인증을 구현할 수 있다.
User model
User model의 기본적으로 있는 여러 필드들이 있다.
-
username
필수사항이다. 150자 이하, 영숫자를 포함하도록 기본적인 vaildate가 있다.
-
first_name
선택사항이다. 30자 이하
-
last_name
선택사항. 150자 이하
-
email
선택사항
-
password
필수 사항. 설정한 암호의 해시값과 메타데이터값이다. 장고는 원래 암호를 그대로 저장하지 않고 특정 알고리즘으로 암호화후 저장한다.
-
groups
그룹에 대한 필드이다.
-
user_permissions
유저의 권한을 설정하는 필드
-
is_staff
참이면 admin 사이트에 접속할 수 있다.
-
is_active
이 계정이 활성인지를 결정.
-
is_superuser
모든 권한을 갖게 한다.Boolean. Designates that this user has all permissions without explicitly assigning them.
-
last_login
마지막으로 로그인한 시간을 기록
-
date_joined
계정이 생성된 날짜를 기록
유저 확장
기본 필드들에 만족하고 사용하면 좋겠지만 기존 User model에서 추가, 수정, 삭제하고 싶은 경우도 있다. 그러기 위한 3가지 방법이 있다.
- Proxy Model
- User model 과 One-To-One 연결
- AbstractBaseUser
- AbstractUser
Proxy Model
User 모델을 직접 상속하고 class Meta
에서 proxy=True
속성으로 Proxy model임을 설정할 수 있다.
이 방법은 기존의 User 스키마는 그대로 두고 기존 동작을 변경하거나 추가하는데 사용된다.
from django.contrib.auth.models import User
from .managers import PersonManager
class Person(User):
objects = PersonManager()
class Meta:
proxy = True
ordering = ('first_name', )
def do_something(self):
...
이 예시에서 정렬을 first_name
으로 했다. do_something()
처럼 메소드를 추가해 새로운 동작을 추가할 수도 있다.
하지만 필드를 바꾸지 못하니 자주 사용하진 않는 방법이다.
User model 과 One-To-One 연결
User 객체가 생성될 때 같이 연결된 사용자 모델이 같이 생성되게 하는 방법이다. 기존 User 모델에 손상주지 않으면서 새 필드들을 추가할 수 있다.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
receiver
를 사용하면 이벤트가 발생할 때를 찾을 수 있다. Save 이벤트가 발생할때마다 create_user_profile
와 save_user_profile
를 호출해 User가 생성될때 Profile 모델도 생성되도록한다.
템플릿에서 다음과 같이 사용할 수 있다.
<h2></h2>
<ul>
<li>Username: </li>
<li>Location: </li>
<li>Birth Date: </li>
</ul>
view.py에서는 다음과 같이 사용할 수 있다.
def update_profile(request, user_id):
user = User.objects.get(pk=user_id)
user.profile.bio = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit...'
user.save()
form 만들기
- forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('url', 'location', 'company')
- view.py
@login_required
@transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.profile)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, _('Your profile was successfully updated!'))
return redirect('settings:profile')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'profiles/profile.html', {
'user_form': user_form,
'profile_form': profile_form
})
- profile.html
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<button type="submit">Save changes</button>
</form>
AbstractBaseUser
완전히 새로운 User 모델을 상속받아 새로 정의한다. 데이터 스키마에 영향을 많이 주기 때문에 주의하며 사용해야한다. 기존 필드뿐만 아니라 동작까지 다 구현한다.
from __future__ import unicode_literals
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
User 모델을 관리하는 Manager도 정의해야한다.
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('The given email 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_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
그리고 이 User를 사용하기 위해 setting.py
에서 필드를 추가한다.
AUTH_USER_MODEL = 'core.User'
참조하는 법
이 모델을 다른 모델에서 참조하는 방법은 2가지가 있다.
from django.db import models
from testapp.core.models import User
class Course(models.Model):
slug = models.SlugField(max_length=100)
name = models.CharField(max_length=100)
tutor = models.ForeignKey(User, on_delete=models.CASCADE)
재사용하고 싶거나 공개로 하고 싶을때는 다음과 같이 한다.
from django.db import models
from testapp.core.models import User
class Course(models.Model):
slug = models.SlugField(max_length=100)
name = models.CharField(max_length=100)
tutor = models.ForeignKey(User, on_delete=models.CASCADE)
AbstractUser
User에서 동작은 그대로 하고 필드만 재정의할 때 사용한다.
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
이렇게 하면 기존 필드에서 정의한 필드가 추가된다. 똑같이 setting.py
에서 이 User를 사용한다고 명시한다.
AUTH_USER_MODEL = 'core.User'