✨ 목차
- 프로젝트 상황
- TDD 방식으로 Admin 페이지 테스트 작성
- 발생한 오류 분석
- 원인: 커스텀 User 모델과 Django 기본 Admin의 충돌
- 해결 방법: UserAdmin 커스터마이징
- 마무리하며
1. 프로젝트 상황
현재 Django 심화 강의를 들으며 TDD 방식으로 프로젝트를 구성하고 있습니다.
관리자(Admin) 페이지를 세팅하는 단계에서 다음과 같은 테스트 코드를 작성했습니다.
# core/tests/test_admin.py
class AdminSiteTests(TestCase):
def setUp(self):
self.client = Client()
self.admin_user = get_user_model().objects.create_superuser(
email='admin@example.com',
password='testpass123',
)
self.client.force_login(self.admin_user)
self.user = get_user_model().objects.create_user(
email='user@example.com',
password='testpass123',
name='Test User'
)
def test_user_list(self):
url = reverse('admin:core_user_changelist')
res = self.client.get(url)
self.assertContains(res, self.user.name)
self.assertContains(res, self.user.email)
def test_edit_user_page(self):
url = reverse('admin:core_user_change', args=[self.user.id])
res = self.client.get(url)
self.assertEqual(res.status_code, 200)
def test_create_user_page(self):
url = reverse('admin:core_user_add')
res = self.client.get(url)
self.assertEqual(res.status_code, 200)
2. TDD 기반 개발 중 발생한 에러
테스트를 실행하자, 모든 테스트가 통과하지는 않았습니다.
python manage.py test
다음과 같은 에러가 발생했죠:
FieldError: Unknown field(s) (username) specified for User.
3. 오류 원인 분석
이 에러 메시지는 Django의 admin.py에 등록한 UserAdmin 클래스가 존재하지 않는 필드 username을 사용하고 있다는 것을 뜻합니다.
그런데 저는 AbstractBaseUser를 상속받은 커스텀 유저 모델을 사용 중이고,
이 모델은 email을 유일한 식별자로 사용하도록 설계했습니다. 즉, username 필드는 애초에 존재하지 않습니다.
하지만 Django의 기본 UserAdmin은 username, first_name, last_name 등을 자동으로 참조하게 되어 있어 충돌이 발생한 것입니다.
4. 원인 요약
- ✅ 나는 email을 아이디로 사용하는 커스텀 User 모델을 만들었음
- ❌ 그런데 기본 UserAdmin은 여전히 username을 포함한 필드를 참조함
- ⚠ 따라서 admin:core_user_add 페이지 (유저 생성 페이지) 테스트에서 오류 발생
5. 해결 방법 – UserAdmin 커스터마이징
admin.py에서 UserAdmin 클래스를 오버라이딩해서 username을 완전히 제거해야 합니다.
또한, add_fieldsets도 반드시 명시해줘야 합니다. 안 그러면 user 생성 페이지에서 다시 기본 필드셋을 참조해 에러가 납니다.
# core/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext_lazy as _
from core import models
class UserAdmin(BaseUserAdmin):
"""Define the admin pages for users."""
ordering = ['id']
list_display = ['email', 'name']
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Permissions'), {
'fields': (
'is_active',
'is_staff',
'is_superuser',
)
}),
(_('Important dates'), {'fields': ('last_login',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
readonly_fields = ['last_login']
admin.site.register(models.User, UserAdmin)
이렇게 설정한 후 다시 테스트를 실행하면... 🎉
OK
성공적으로 모든 테스트가 통과합니다.
6. 마무리하며
TDD 방식으로 개발할 때의 장점은 문제가 생겼을 때 빠르게 탐지할 수 있다는 점입니다.
이번 오류도 미리 작성한 테스트 덕분에 admin 페이지가 잘못 설정된 사실을 빠르게 알 수 있었습니다.
또한, 커스텀 유저 모델을 쓸 때는 Django 기본 Admin 설정을 반드시 직접 커스터마이징해야 한다는 점도 배웠습니다.
앞으로도 TDD 기반으로 차근차근 개발하면서, 이런 시행착오들을 기록해보려 합니다.
도움이 되셨다면 댓글이나 공감 부탁드립니다 🙌
'Programming > Django' 카테고리의 다른 글
| 🔌 API란 무엇일까? 쉽게 풀어보는 API의 개념과 동작 원리 (3) | 2025.08.06 |
|---|---|
| ✅ TDD란 무엇인가? 테스트 주도 개발을 처음 접하는 분들을 위한 설명 (3) | 2025.08.06 |
| 🗄️ Django & SQL에서의 CASCADE와 NOT NULL 이해하기 (3) | 2025.08.05 |
| 🧪 Python Mock 완벽 가이드 — 테스트에서 가짜 객체를 쓰는 이유 (5) | 2025.08.05 |
| 🧪 테스트 주도 개발(TDD) 완벽 가이드 (4) | 2025.08.04 |