바뀜

2,762 바이트 추가됨 ,  2022년 12월 15일 (목) 13:38
편집 요약 없음
1번째 줄: 1번째 줄:  
[[분류:장고 기능구현(초급)]]
 
[[분류:장고 기능구현(초급)]]
 
==개요==
 
==개요==
기본적으로 제공되는 유저모델은 제한적이다. 학교에서 운영한다면 학번 등의 정보를 저정해야 하는데, 이처럼 제공하지 않는 기능들을 확장하는 과정이 필요하다.
     −
장고에서 기본적으로 제공해주는 항목을 넘어 개별항목을 지정하는 등의 작업을 하기 위해 처음부터 커스텀유저를 사용하길 권장한다.
+
=== 시작에 앞서... ===
 +
# 프로젝트의 시작 전에 구현해야 한다.
 +
#:- 기존에 가입된 회원들이 있는 상태에서 새로운 DB 테이블을 정의할 때, migrate 따위의 명령을 실행하면 <code>django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency 앱이름.0001_initial on database 'default'.</code> 같은 에러가 뜬다. 가장 간단한 해결법은 기존 DB를 삭제하고 다시 처음부터 설계를 반영하는 것이다. 때문에 이런 불상사를 막으려면 프로젝트를 제대로 시작하기 전에 최소한의 앱과 커스텀 유저는 구현해 두어야 한다.
 +
#:- 만약 프로젝트의 중간에 추가해 넣어야 한다면 다음의 문서를 참고하자. [https://code.djangoproject.com/ticket/25313 링크.] 개빡센 여정이 예상된다.
 +
 
 +
* 기본적으로 제공되는 유저모델은 제한적이다. 학교에서 운영한다면 학번 등의 정보를 저정해야 하는데, 이처럼 제공하지 않는 기능들을 확장하는 과정이 필요하다.
 +
* 장고에서 기본적으로 제공해주는 항목을 넘어 개별항목을 지정하는 등의 작업을 하기 위해 처음부터 커스텀유저를 사용하길 권장한다.
 +
* 일반적으로 본격적인 프로젝트를 시작하기 전에 만들기가 권장된다. 프로젝트 도중에 모델을 바꾸는 것은 DB의 왜래키나 다대다 관계에 영향을 미치는데, 이를 다시 고치는 일은 꽤 어려운 일이기 때문이다.(중간에 커스텀모델을 추가하는 경우엔 DB자체를 지우고, 다시 구성한다.) 장고의 의존성 특성 때문에 최초의 DB에 생성되어 포함되어야 한다.
 
{| class="wikitable"
 
{| class="wikitable"
 
|+유저 기능을 확장하는 방법<ref>https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html</ref>
 
|+유저 기능을 확장하는 방법<ref>https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html</ref>
27번째 줄: 33번째 줄:     
기본 속성으로 id(기본키), password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined 필드가 들어있다.
 
기본 속성으로 id(기본키), password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined 필드가 들어있다.
|}일반적으로 본격적인 프로젝트를 시작하기 전에 만들기가 권장된다. 프로젝트 도중에 모델을 바꾸는 것은 DB의 왜래키나 다대다 관계에 영향을 미치는데, 이를 다시 고치는 일은 꽤 어려운 일이기 때문이다.(중간에 커스텀모델을 추가하는 경우엔 DB자체를 지우고, 다시 구성한다.) 장고의 의존성 특성 때문에 최초의 DB에 생성되어 포함되어야 한다.
+
|}
 
===사용하는 것은 AbstractBaseUser===
 
===사용하는 것은 AbstractBaseUser===
 
AbstractUser는 크게 변경하거나 확장하는 내용이 많지 않다.(그냥 Profile 방식을 사용해도 되지 않을까 싶을 정도로..) 하여, 여기에선 조금 어렵지만, 더 자유로운 BaseUser에 대해 다뤄보고자 한다.
 
AbstractUser는 크게 변경하거나 확장하는 내용이 많지 않다.(그냥 Profile 방식을 사용해도 되지 않을까 싶을 정도로..) 하여, 여기에선 조금 어렵지만, 더 자유로운 BaseUser에 대해 다뤄보고자 한다.
 +
 
==사전작업==
 
==사전작업==
어떤 앱의 어떤 모델을 기본 유저로 사용할지 생각하고 진행한다.
+
어떤 앱의 어떤 모델을 기본 유저로 사용할지 생각하고 진행한다.(그냥 앱을 새로 파는 게 적절하다.)
 +
==모델 작성==
   −
===settings.py에 만들 모델 추가===
+
* 필수적으로 2개의 모델을 작성해주어야 한다. BaseUserManager를 상속받은 모델과 AbstractBaseUser를 상속받은 모델.
보통은 앱이름은 account, 모델이름은 MyUser, Account, CustomUser, User 따위가 된다.<syntaxhighlight lang="python">
+
* 사람마다 짜는 방식이 달라서, 그리고 일일이 주석을 달아두지 않기 때문에 처음 하는 사람들은 해석하는 데 적잖이 애먹는다.  
AUTH_USER_MODEL = '앱이름.모델이름'  # 관리유저로 사용할 모델을 설정한다.
+
* 아래에선 계정 식별자를 identifier로 설정했는데, 장고에서 기본적으로 사용하는 username 필드를 사용하는 편이 좋다.(권한 관련 확장기능에서 username을 그대로 사용하는 경우가 많아, 계정 식별자는 username을 사용하는 편이 좋다.)
   −
</syntaxhighlight>
  −
==모델 작성==
  −
필수적으로 2개의 모델을 작성해주어야 한다. BaseUserManager를 상속받은 모델과 AbstractBaseUser를 상속받은 모델.
  −
  −
사람마다 짜는 방식이 달라서, 그리고 일일이 주석을 달아두지 않기 때문에 처음 하는 사람들은 해석하는 데 적잖이 애먹는다.
   
{| class="wikitable"
 
{| class="wikitable"
 
!과정
 
!과정
51번째 줄: 54번째 줄:  
|<syntaxhighlight lang="python">
 
|<syntaxhighlight lang="python">
 
from django.db import models
 
from django.db import models
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)
+
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|-
 
|-
57번째 줄: 60번째 줄:  
|유저를 생성할 때 사용하는 헬퍼.
 
|유저를 생성할 때 사용하는 헬퍼.
 
AbstractBaseUser가 참고하니, 그보다 위에 작성되어야 한다.
 
AbstractBaseUser가 참고하니, 그보다 위에 작성되어야 한다.
 +
       
인수로 받는 email 등을 다른 것으로 바꿀 수 있다.
 
인수로 받는 email 등을 다른 것으로 바꿀 수 있다.
 +
      97번째 줄: 102번째 줄:  
|관리자 계정인가.
 
|관리자 계정인가.
 
|}
 
|}
기타 필드
+
'''필수인듯 필수 아닌 기타 필드'''
 +
 
 +
꼭 정의되지 않아도 되지만, 정의되지 않으면 admin 페이지 접속 자체가 안된다.
 
{| class="wikitable"
 
{| class="wikitable"
!필수필드
+
!기타필드 및 메서드
 
!설명
 
!설명
 
|-
 
|-
 
|is_staff
 
|is_staff
 
|어드민에 접속할 권한.
 
|어드민에 접속할 권한.
 +
|-
 +
|has_perm
 +
|<syntaxhighlight lang="python3">
 +
def has_perm(self, perm, obj=None):
 +
    '''권한 소지여부를 판단하기 위한 메서드'''
 +
    return True
 +
</syntaxhighlight>
 +
|-
 +
|has_module_perms
 +
|<syntaxhighlight lang="python3">
 +
def has_module_perms(self, app_label):
 +
    '''앱 라벨을 받아, 해당 앱에 접근 가능한지 파악'''
 +
    return True
 +
</syntaxhighlight>
 +
|}
 +
'''기타 필드'''
 +
{| class="wikitable"
 +
!기타필드
 +
!설명
 
|-
 
|-
 
|is_superuser
 
|is_superuser
 
|그냥 모든 권한.
 
|그냥 모든 권한.
 
|}
 
|}
 +
last_login 필드는 자동으로 생성된다.
 
|<syntaxhighlight lang="python">
 
|<syntaxhighlight lang="python">
 
class User(AbstractBaseUser):
 
class User(AbstractBaseUser):
 
     identifier = models.CharField(max_length=20, unique=True)
 
     identifier = models.CharField(max_length=20, unique=True)
 
     is_active = models.BooleanField(default=True)
 
     is_active = models.BooleanField(default=True)
 +
    is_staff = models.BooleanField(default=False)
 
     is_admin = models.BooleanField(default=False)
 
     is_admin = models.BooleanField(default=False)
   142번째 줄: 170번째 줄:     
===DB에 반영===
 
===DB에 반영===
이 작업을 처음에 하는 게 아니라, 개발 중에 하는 경우, 다른 앱의 모델에서 유저를 참조하고 있을 때 참조테이블로 User가 들어가 있는데, 이 때문에 'auth.User', which has been swapped out. 라는 에러가 뜬다.
+
이 작업을 처음에 하는 게 아니라, 개발 중에 하는 경우, 다른 앱의 모델에서 유저를 참조하고 있을 때 참조 테이블로 User가 들어가 있는데, 이 때문에 'auth.User', which has been swapped out. 라는 에러가 뜬다.
    
이것과 from django.contrib.auth.models import User를 지우고, from django.conf import settings 후에
 
이것과 from django.contrib.auth.models import User를 지우고, from django.conf import settings 후에
   −
User 대신 settings.AUTH_USER_MODEL를 넣어주면 된다.
+
User 대신 <code>settings.AUTH_USER_MODEL</code>를 넣어주면 된다.
 +
 
 +
위 <code>settings.AUTH_USER_MODEL</code>은 텍스트만 반환하기 때문에, 유저 객체 자체를 불러오고 싶다면 <code>from django.contrib.auth import get_user_model</code> 을 사용하면 된다.
 +
===settings.py에 만들 모델 추가===
 +
아래 작업은 DB 반영이 끝나 후에 진행해야 한다. 그렇지 않으면 <code>ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'account.user', but app 'account' isn't installed.</code> 따위의 에러가 발생한다.
 +
 
 +
다음과 같은 줄을 settings.py 내에 추가한다.
 +
 
 +
보통은 앱이름은 custom_account, 모델 이름은 User 따위가 된다.<syntaxhighlight lang="python">
 +
AUTH_USER_MODEL = 'custom_account.User'  # 관리유저로 사용할 모델을 설정한다.
 +
</syntaxhighlight>
 +
 
 +
=== 중간 확인 ===
 +
 
 +
* python manage.py createsuperuser로 관리 계정 생성.
 +
* 사이트를 실행시킨 후 /admin에 들어가 로그인해본다.
 +
 
 +
==관리자 화면에 등록==
 +
아직 관리자 화면에선 가입한 유저들의 정보가 나오지 않는다. 이들을 한눈에 관리하기 위해 admin.py를 작성한다.<syntaxhighlight lang="python">
 +
from django.contrib import admin
 +
from .models import User  # 직접 등록한 모델
 +
 
 +
@admin.register(User)
 +
class UserAdmin(admin.ModelAdmin):
 +
    list_display = ('identifier',)
 +
    exclude = ('password',)  # 사용자 상세 정보에서 비밀번호 필드를 노출하지 않음
 +
</syntaxhighlight>그럼 이제 이 모델로 계정 관리가 가능해진다.
 +
 
 
==폼 작성==
 
==폼 작성==
모델 작성은 끝났는데, 해당 정보를 기입하기 위한 폼이 필요하다. 기본 폼은 password 따위를 암호화하지 않고 그대로 저장하기 때문이다. 폼을 밑바닥부터 만들려면 알아야 할 것도 많은데, 직접 만들기보단, UserCreationForm을 이용해 폼을 다뤄보자.
+
모델 작성은 끝났는데, 해당 정보를 기입하기 위한 폼이 필요하다. 회원가입 시에도 필요하고.
 +
 
 +
기본 폼은 password 따위를 암호화하지 않고 그대로 저장하기 때문이다. 폼을 밑바닥부터 만들려면 알아야 할 것도 많은데, 직접 만들기보단, UserCreationForm을 이용해 폼을 다뤄보자.
    
앱 안에 forms.py를 만들어 작성하자.
 
앱 안에 forms.py를 만들어 작성하자.
159번째 줄: 216번째 줄:  
class User_create_form(UserCreationForm):
 
class User_create_form(UserCreationForm):
 
     class Meta:
 
     class Meta:
         model = get_user_model  #  설정된 커스텀모델
+
         model = get_user_model() #  설정된 커스텀모델
 
         fields = ["identifier"]  # password1,2 필드는 자동추가된다.
 
         fields = ["identifier"]  # password1,2 필드는 자동추가된다.
    +
# 아래 코드는 유저정보 수정을 위한 것으로, 없어도 무방하다.
 
class User_change_form(UserChangeForm):
 
class User_change_form(UserChangeForm):
 
     class Meta:
 
     class Meta:
         model = get_user_model
+
         model = get_user_model()
 
         fields = ["identifier", "password1", "password2"]
 
         fields = ["identifier", "password1", "password2"]
 
</syntaxhighlight>password부분은 UserCreationForm에 정의된 것들이라 오버라이드 해줘야 한다.
 
</syntaxhighlight>password부분은 UserCreationForm에 정의된 것들이라 오버라이드 해줘야 한다.
170번째 줄: 228번째 줄:  
비밀번호 조건은 settings.py의 AUTH_PASSWORD_VALIDATORS 안에 있는 조건들을 거쳐야 한다.
 
비밀번호 조건은 settings.py의 AUTH_PASSWORD_VALIDATORS 안에 있는 조건들을 거쳐야 한다.
   −
  −
==관리자 화면에 등록==
  −
admin.py를 작성한다.<syntaxhighlight lang="python">
  −
from django.contrib import admin
  −
from .models import User  # 직접 등록한 모델
  −
#from django.contrib.auth import get_user_model은 안되나?? 확인해보자.
        −
@admin.register(User)
  −
class UserAdmin(admin.ModelAdmin):
  −
    list_display = ('identifier')
  −
    list_display_links = ('identifier')
  −
    exclude = ('password',)  # 사용자 상세 정보에서 비밀번호 필드를 노출하지 않음
  −
</syntaxhighlight>그럼 이제 이 모델로 계정관리가 가능해진다.
   
==모델==
 
==모델==
 
커스텀유저를 외래키로 사용하고 싶다면
 
커스텀유저를 외래키로 사용하고 싶다면