- Published on
django-unfold로 Admin 교체하고 점진 전환한 방법
- Authors

- Name
- hongreat
- ✉️hongreat95@gmail.com
운영툴로 Django Admin을 무겁게 사용하고 있습니다.
기본 어드민 UI가 기능적으로는 문제가 없지만 확실히 투박하고, 예전에 많이들 쓰던 django-jet 같은 어드민 스킨들은 유지보수가 끊긴지 오래라 대안을 찾고 있었습니다.
그러다 django-unfold를 검토하게 되었고, 전사 어드민에 도입했습니다.
전체를 한번에 갈아엎지 않고 점진적으로 전환했는데, 이 과정에서 정리한 것들을 기록합니다.
1. unfold를 선택한 이유
어드민 스킨 계열 라이브러리를 고를때 제일 중요하게 본 것은 디자인이 아니라 유지보수 상태였습니다.
- 릴리즈가 활발하고 Django 최신 버전(5.x)을 바로 따라간다
- Tailwind 기반이라 UI가 현대적이고, 다크모드가 기본 지원된다
- 기존
ModelAdmin상속 구조를 그대로 유지한 채 베이스 클래스만 바꾸면 된다 simple_history,import_export,filters같은 contrib 패키지로 서드파티 연동을 공식 지원한다
특히 세번째가 컸습니다. 어드민 클래스가 수십개인 프로젝트에서 등록 방식 자체가 바뀌는 라이브러리였다면 도입할 엄두를 못냈을 것 입니다.

2. 기본 적용 방법
2.1 INSTALLED_APPS 순서가 중요하다
unfold는 django.contrib.admin보다 반드시 먼저 선언해야 합니다.
INSTALLED_APPS = [
"unfold",
"unfold.contrib.filters", # 사용하는 경우
"unfold.contrib.simple_history", # django-simple-history 쓰는 경우
"unfold.contrib.import_export", # django-import-export 쓰는 경우
"django.contrib.admin",
...
]
이유는 Django의 앱 템플릿 로더가 INSTALLED_APPS 순서대로 템플릿을 찾기 때문입니다.
unfold는 admin/base_site.html 같은 어드민 템플릿을 오버라이드하는 방식으로 동작하는데, 직접 확인해보면 순서에 따라 로드되는 템플릿이 달라집니다.
unfold가 먼저 -> unfold/templates/admin/base_site.html (정상)
admin이 먼저 -> django/contrib/admin/templates/admin/base_site.html (unfold 무시됨)
순서가 틀려도 에러는 나지 않고 그냥 기본 어드민이 뜨기 때문에, 처음 적용할때 헷갈릴 수 있는 부분입니다.
2.2 ModelAdmin 교체
각 어드민 클래스의 베이스를 unfold의 ModelAdmin으로 바꿔줍니다. Inline도 마찬가지입니다.
from unfold.admin import ModelAdmin, TabularInline
class OrderItemInline(TabularInline):
model = OrderItem
@admin.register(Order)
class OrderAdmin(ModelAdmin):
list_display = ["id", "user", "status", "created_at"]
inlines = [OrderItemInline]
여기서 주의할 점은, django.contrib.admin.ModelAdmin을 그대로 상속한 클래스도 화면에 뜨기는 뜬다는 것 입니다. 다만 unfold 스타일이 적용되지 않은 어색한 화면이 됩니다.
에러가 아니라서 오히려 놓치기 쉬운데, 반대로 생각하면 이 특성 덕분에 점진 전환이 가능합니다.
2.3 UNFOLD 설정
settings에 UNFOLD dict로 사이트 전반을 설정합니다. 실제로 사용중인 설정 위주로 추리면 이정도입니다.
UNFOLD = {
"SITE_TITLE": "Service Admin",
"SITE_HEADER": "Service Admin",
"SHOW_HISTORY": True, # 우측 상단 히스토리 버튼
"SHOW_VIEW_ON_SITE": True,
"SHOW_BACK_BUTTON": True,
"SIDEBAR": {
"show_search": True, # 사이드바 검색
"show_all_applications": True,
},
}
3. 점진 전환: 공통 베이스 클래스 하나로
어드민 클래스가 많아서 전부 한번에 바꾸는 대신, 프로젝트 공통 베이스 클래스를 하나 만들었습니다.
# utils/admin.py
from unfold.admin import ModelAdmin as UnfoldModelAdmin
class BaseModelAdmin(UnfoldModelAdmin):
list_filter_submit = True # 필터를 선택 즉시가 아니라 버튼 클릭시 적용
class Media:
js = ("admin/js/disable_number_scroll.js",)
이후의 전환 작업은 각 어드민이 이 클래스를 상속하도록 바꾸는 단순 작업이 됩니다. 그리고 프로젝트 전체에 적용할 옵션이 생길때마다 이 베이스에만 추가하면 됩니다.
list_filter_submit = True는 써보고 나서 기본값으로 박아둔 옵션입니다.
unfold의 필터는 기본적으로 선택 즉시 적용되는데, 필터 조건을 여러개 거는 운영자 입장에서는 조건 하나 선택할때마다 리스트가 리로드되는게 오히려 불편했습니다. 이 옵션을 켜면 조건을 다 고른 뒤 버튼으로 한번에 적용할 수 있습니다.
4. 미리 알아두면 좋은 포인트
전환하면서 부딪혔던 지점들을 짧게 정리합니다.
- 기존 커스텀 어드민 믹스인이 있다면 베이스를 통일해야 합니다.
django.contrib.admin.ModelAdmin기준으로 만들어둔 믹스인과 unfold의ModelAdmin을 섞어 상속하면 MRO에 따라 unfold 쪽 동작이 가려질 수 있습니다. 저희는 공통 믹스인들의 베이스를 unfoldModelAdmin으로 바꿔서 해결했습니다. change_list.html등을 오버라이드한 커스텀 템플릿은 unfold 템플릿 기준으로 다시 맞춰야 합니다. 기본 어드민 템플릿을 extend 하고 있으면 해당 화면만 옛날 화면이 됩니다.- 커스텀 Form을 쓰는 화면은 위젯도
unfold.widgets의 것들(UnfoldAdminSelect2Widget등)로 바꿔야 화면 톤이 유지됩니다. 안바꿔도 동작은 하는데 그 위젯만 기본 스타일로 떠서 이질감이 큽니다. - 서드파티 어드민 확장(simple_history 등)은 contrib 모듈을 INSTALLED_APPS에 추가하는 것을 잊으면 해당 화면만 스타일이 깨집니다.
공통점은 전부 "에러가 나지 않고 화면이 어색해질 뿐"이라는 점입니다. 그래서 전환 기간에는 기능 테스트보다 화면을 직접 눌러보는 확인이 더 중요했습니다.
도입하고 나서 팀 내부 만족도가 생각보다 높았습니다.
운영툴은 매일 쓰는 사람이 따로 있는 도구라서, UI 개선이 곧 업무 효율로 이어진다는 것을 체감했습니다.
Django Admin을 운영툴로 무겁게 쓰고 있고 jet 시절의 스킨에서 넘어오지 못했다면, unfold는 충분히 검토할 가치가 있다고 생각합니다.
