시작
Part 6에 이어서 간단한 설문조사(Polls) 앱을 만드는 과정을 통해 Django의 Admin 사이트 커스터마이징 방법을 알아보려고 합니다. 본 포스트에서는 macOS와 IntelliJ IDEA Ultimate을 사용합니다.
본문
Admin Form 커스터마이징
admin.site.register(Question)
과 같이 Question
을 등록하면 Django는 기본 form을 구성할 수 있습니다
polls/admin.py
를 아래처럼 수정합니다.
from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fields = ["pub_date", "question_text"]
admin.site.register(Question, QuestionAdmin)
이 변경으로 "Publication date"가 "Question" 필드 앞에 오게 됩니다.
이렇게 form의 필드 순서를 관리할 수 있습니다.
또한 form의 여러 필드를 세트로 나누어 구성할 수도 있습니다.
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
admin.site.register(Question, QuestionAdmin)
fieldsets
에 있는 각 튜플에서 첫 번째 요소는 fieldset
의 제목이 됩니다.
관련 객체 추가하기
Question
관리 페이지에는 Question
만 표시되고 Choices
가 없습니다.
이 문제를 해결하는 방법에는 두 가지가 있습니다. 첫 번째는 Choice
모델을 등록하는 것입니다.
admin.site.register(Choice)
해당 form에서 Question
필드는 데이터베이스의 모든 Question
을 포함하는 선택 상자가 됩니다. Django는 ForeignKey가 관리자 페이지에서 <select>
박스로 표시되어야 한다는 것을 알고 있습니다.
하지만 실제로 이렇게 Choice
객체를 추가하는 것은 비효율적입니다. Question
객체를 만들 때 여러 Choice
를 직접 추가하는 방법이 더 효율적일 수 있습니다.
polls/admin.py
를 수정합니다.
from django.contrib import admin
from .models import Choice, Question
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"], "classes": ["collapse"]}),
]
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)
이렇게 하면 Django는 Choice
객체가 Question
관리자 페이지에서 편집되고 기본적으로 3개의 선택 항목을 제공해야 한다고 알리게 됩니다.
Question
추가 페이지에 Choice
가 아래와 같이 추가됩니다.
하지만 한 가지 작은 문제가 있습니다. 관련된 Choice
객체를 입력하기 위해 많은 화면 공간을 차지합니다. 이러한 이유로 Django는 inline 관련 객체를 표시하는 tabular
방식을 제공합니다. ChoiceInline
을 변경합니다.
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
StackedInline
대신 TabularInline
을 사용하면 아래처럼 간결한 테이블 형식으로 표시됩니다.
Admin Change List 커스터마이징
아래 Question change list
페이지를 약간 커스터마이징하겠습니다.
기본적으로 Django는 각 객체의 str()
을 표시합니다. 하지만 때로는 개별 필드를 표시하는 것이 더 좋을 수 있습니다. 이를 해결하기 위해 객체의 변경 목록 페이지에 표시할 필드 이름 목록인 list_display
관리 옵션을 사용할 수 있습니다.
polls/admin.py
의 QuestionAdmin
에 list_display
를 추가합니다.
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ["question_text", "pub_date", "was_published_recently"]
Question change list
가 아래처럼 변경됩니다.
일반적으로 각 열의 헤더를 클릭하면 해당 값을 기준으로 정렬할 수 있습니다. 그러나 was_published_recently
헤더와 같이 임의 메서드의 출력값으로는 정렬이 지원되지 않습니다. 기본적으로 메서드 이름(밑줄은 공백으로 대체됨)이 헤더 이름이 됩니다.
다음과 같이 polls/models.py
에서 display()
데코레이터를 사용하여 이를 개선할 수 있습니다.
from django.contrib import admin
class Question(models.Model):
# ...
@admin.display(
boolean=True,
ordering="pub_date",
description="Published recently?",
)
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
그리고 polls/admin.py
의 QuestionAdmin
에 list_filter
를 사용하여 필터링 기능을 추가할 수 있습니다.
class QuestionAdmin(admin.ModelAdmin):
# ...
list_filter = ["pub_date"]
아래처럼 필터링 사이드바가 추가됩니다.
표시되는 필터 유형은 필터링하는 필드 유형에 따라 다릅니다. pub_date
가 DateTimeField
이기 때문에 Django
는 언제나
,오늘
,지난 7일
,이번 달
,이번 해
와 같은 적절한 필터 옵션을 제공합니다.
검색 기능도 추가해 보겠습니다.
class QuestionAdmin(admin.ModelAdmin):
# ...
search_fields = ["question_text"]
아래처럼 검색 박스가 추가됩니다.
이 검색은 LIKE
쿼리를 사용합니다.
Admin Look and Feel을 커스터마이징
프로젝트 템플릿 사용자 정의
설정 파일(mysite/settings.py
)을 열고 설정 DIRS에 옵션을 추가합니다.
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
DIRS
는 Django가 템플릿을 로드할 때 확인하는 디렉터리 목록으로 검색 경로 지정하는 역할을 합니다.
이제 django/contrib/admin/templates/admin
에 있는 base_site.html
를 복사하여 templates/admin/base_site.html
를 만듭니다.
{% extends "admin/base.html" %}
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
{% block nav-global %}{% endblock %}
그런 다음 {{ site_header|default:_('Django administration') }}
를 Polls Administration
으로 변경합니다.
{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
이런 방법을 사용하여 템플릿을 재정의할 수 있습니다.
실제 프로젝트에서는 django.contrib.admin.AdminSite.site_header
속성을 사용하여 이러한 사용자 정의를 더 쉽게 수행할 수 있습니다.
from django.contrib import admin
from .models import MyModel
class MyAdminSite(admin.AdminSite):
site_header = "Monty Python administration"
admin_site = MyAdminSite(name="myadmin")
admin_site.register(MyModel)
DIRS가 기본적으로 비어 있었는데 Django가 기본 관리자 템플릿을 어떻게 찾고 있었을까요?
APP_DIRS = True로 설정되어 있기 때문에 Django는 자동으로 각 애플리케이션 패키지 내의 templates/ 하위 디렉터리를 찾습니다.
마무리
Part 7에서는 간단히 Django Admin 사이트를 커스터마이징 하는 다양한 방법을 살펴보았습니다. Django의 기본 제공 기능만으로도 강력한 관리자 페이지를 쉽게 구축할 수 있고 커스터마이징이 필요할 때도 쉽게 가능하다는 점에서 유연성이 뛰어납니다. 이를 통해 개발 속도가 빨라지고 더 편리하게 작업할 수 있을 것 같습니다.
참고자료
'Django' 카테고리의 다른 글
DRF Tutorial 1 Serialization (0) | 2024.09.11 |
---|---|
첫 번째 Django 앱 만들기 (Part 8: Adding third-party packages) (1) | 2024.09.02 |
첫 번째 Django 앱 만들기 (Part 6: Static files) (0) | 2024.08.22 |
첫 번째 Django 앱 만들기 (Part 5: Testing) (0) | 2024.08.21 |
첫 번째 Django 앱 만들기 (Part 4: Forms and generic) (0) | 2024.08.19 |
댓글