[17. Django] 사용자 관리 (250710 수업)

해피해피슈크림·2025년 7월 10일

사용자 관리 app

App 생성, User Model 정의

  • App을 생성
    • python manage.py startapp account -> account 폴더 생김
    • settings.py에 등록 (INSTALLED_APPS)
  • User Model 정의
    • models.py에 User모델클래스 정의
    • settings.py에 User 모델을 등록 (AUTH_USER_MODEL = "account.User")
    • admin app에서 데이터 관리를 위해서 admin.py에 등록 + 화면 구성 설정.

models.py 수정하고 migrate

# account/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

# User 모델 등록
## AbstractUser를 상속 받아서 확장 User 모델로 정의 

class User(AbstractUser):
    # username/password(AbstractUser)를 제외한 나머지 Field들을 정의 
    name = models.CharField(
        verbose_name="이름", # Form 관련 설정. ModelForm을 만들 경우 form 관련 설정을 Model field에 할 수 있다. 
        max_length=50 # varchar(50)
        )
    email = models.EmailField(verbose_name="Email", max_length=100)
    # varchar(100) -> 검증기능이 추가: 값이 이메일 형식(@를 포함하는지)인지 여부를 검증
    birthday = models.DateField(
        verbose_name="생일",
        null=True, # nullable # default: not null
        blank=True, # 입력폼 설정 - 빈값입력 가능 여부(default: False - required) # null=True와 같이 준다. 
    )
    
    def __str__(self):
        return f"{self.username} - {self.name}"

# python manage.py makemigrations
# python manage.py migrate

마이그레이션 문제 발생

1. 마이그레이션 관련 오류가 떠서 perplexity에게 물어봤다.

오류 원인: InconsistentMigrationHistory
오류 메시지의 핵심은 다음과 같습니다:

Migration admin.0001_initial is applied before its dependency account.0001_initial on database 'default'.

의미: Django의 admin 앱의 초기 마이그레이션(admin.0001_initial)이 account.0001_initial보다 먼저 적용되어 있다는 뜻입니다.

그런데 admin.0001_initial은 account.0001_initial에 의존성(Dependency)이 있어서, 반드시 account 마이그레이션이 먼저 적용되어야 합니다.

마이그레이션 순서가 꼬여서 Django가 데이터베이스 상태를 일관성 있게 유지할 수 없다고 판단한 것입니다.

➡️ 마이그레이션 순서를 되돌리는 방법을 제시

2. 강사님께서는 DB를 아예 삭제하고 다시 구축하는 방법을 제시하셨다.

  1. sqlite3 삭제
  2. migration 재생성 => DB 재생성됨
  3. create super user

마이그레이션을 다시 하고 super user를 create 해야하는지 몰라서 헤맸다. ㅠㅠ

사용자 추가 화면 구축

코드

# account/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

# User 모델 등록
## AbstractUser를 상속 받아서 확장 User 모델로 정의 

class User(AbstractUser):
    # username/password(AbstractUser)를 제외한 나머지 Field들을 정의 
    name = models.CharField(
        verbose_name="이름", # Form 관련 설정. ModelForm을 만들 경우 form 관련 설정을 Model field에 할 수 있다. 
        max_length=50 # varchar(50)
        )
    email = models.EmailField(verbose_name="Email", max_length=100)
    # varchar(100) -> 검증기능이 추가: 값이 이메일 형식(@를 포함하는지)인지 여부를 검증
    birthday = models.DateField(
        verbose_name="생일",
        null=True, # nullable # default: not null
        blank=True, # 입력폼 설정 - 빈값입력 가능 여부(default: False - required) # null=True와 같이 준다. 
    )
    
    def __str__(self):
        return f"{self.username} - {self.name}"

# settings.py에 사용자 정의 User 모델 등록
# database 삭제 (db.sqlite3 파일)
# python manage.py makemigrations
# python manage.py migrate
# account/admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

# 관리자(admin)에서 User를 어떻게 관리할지 화면을 재구성.
# UserAdmin을 정의
## list_display: admin의 Users(사용자들)의 메인 화면 목록에 나올 항목 등록
## add_fieldsets: Tuple - User 등록 화면에 나올 항목들 지정.
## fieldsets: Tuple - User 수정 화면에 나올 항목들 지정.

class CustomUserAdmin(UserAdmin):
    list_display = ["username", "name", "email"]
    add_fieldsets = (
        ("인증정보", {"fields":("username", "password1", "password2")}), 
        ("개인정보", {"fields":("name", "email", "birthday")})
    )
    fieldsets = (
        ("인증정보", {"fields":("username", "password")}), 
        ("개인정보", {"fields":("name", "email", "birthday")})
    )

admin.site.register(User, CustomUserAdmin)

결과


사용자들 버튼 클릭

사용자 추가 + 버튼을 누르면


인증정보 -> 사용자 이름, 비밀번호, 비밀번호 확인
개인정보 -> 이름, 이메일, 생일


forms.py

# account/forms.py
## Form이나 ModelForm 클래스들을 정의하는 모듈
## 보통 Form은 등록/수정 폼 각각 하나씩 정의.

## User 등록 폼, User 수정 폼 ==> ModelForm

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User

# ModelForm: ModelForm을 상속, Form: forms.Form을 상속

# UserCreationForm에 정의된 Form필드: username, password1, password2
# CustomUserCreationFrom: UserCreationForm의 form필드 + name, email, birthday
class CustomUserCreationForm(UserCreationForm):

    class Meta:
        model = User # User Model의 model field를 이용해서 Form field를 구성.
        fields = "__all__" # 모델의 모든 field들을 이용해서 구성.
        # fields = ["name", "email"] # 특정 model field들을 선택해서 구성.
        # exclude = ["name"] # 지정한 model field를 제외한 나머지를 이용해서 구성. (fields와 exclude는 같이 사용 못한다.)
        

/config/urls.py

# \config\urls.py
urlpatterns = [
    path("", TemplateView.as_view(template_name="home.html"), name="home"),
    path('admin/', admin.site.urls),
    # path('polls/welcome', views.welcome_poll, name="welcome"),
    path("polls/", include('polls.urls')),
    path("account/", include("account.urls")),
]

account/urls.py 파일 생성

먼저 기본 틀을 잡는다.

# account/urls.py

from django.urls import path

from . import views

app_name="account"

urlpatterns = [
    
]

urlpatternspath를 지정해준다.
이때 변수명을 urlpatterns라고 꼭 해줘야 한다. url_patterns라고 적었다가 오류남 ㅠㅠ

# account/urls.py

from django.urls import path

from . import views

app_name="account"

urlpatterns = [
    path("create", views.create, name="create"),
]

settings.py에 앱 등록 - 'django_bootstrap5`

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
    'account',
    'django_bootstrap5', # ⭐ 여기
]

account/views.py 파일 생성

# account/views.py

from django.shortcuts import render
from .forms import CustomUserCreationForm

#########################
# 사용자 가입 처리
# 요청 url: account/create
#   가입이나 수정은 항상 두 단계로 나뉜다. 
#   GET - 가입 폼 양식을 응답
#   POST - 가입 처리
# view 함수: create
# 응답:  GET - templates/account.create.html
#       POST - home으로 이동. redirect 방식으로 (새로고침해도 votes 추가 되지 않게 하기 위해서)

def create(request):
    if request.method == "GET":
        return render(request, "account/create.html", {"form":CustomUserCreationForm()})
    else: # POST
        pass

account 앱 폴더 아래 create.html 파일 생성

<!-- account/templates/account/create.html -->
 {% extends "layouts/main_layout.html" %}
 {% load django_bootstrap5 %}


{% comment %}
django_bootstrap5 사용. django template에서 bootstrap을 적용할 수 있는 태그들을 제공하는 lib.
`pip install django_bootstrap5`
form 입력에 bootstrap을 적용
settings.py에 앱 등록
{% endcomment %}


 {% block title %}회원가입{% endblock title %}

 {% block contents %}
 <h1>회원가입</h1>
 <form method="post">
    {% csrf_token %}
    
    {% bootstrap_form form %}

    <div class="mt3">
        <button type="submit" class="btn btn-primary">가입</button>
        <button type="reset" class="btn btn-primary">초기화</button>
    </div>
 </form>
 {% endblock contents %}

main_layout에 url 등록해주기~~

<a href="{% url 'account:create' %} class=nav-link"></a>

0개의 댓글