관리자 페이지에서는 사용자가 정의한 모델에 대한 기본적인 CRUD 기능을 제공한다. 

그러나 때로는 사용자가 직접 원하는 기능을 추가하고 싶을 수 있다. 

이를 위해서 장고에서는 어드민(관리자) 페이지 커스터마이징 기능도 제공한다. 

 

관리자 페이지 커스터마이징 작업은 admin.py 파일에서 이루어진다. 

우선 각 모델에 해당하는 모델 관리자 클래스를 만들어 놓자. 

 

대략적으로 admin.py 에서 정의한 모델 클래스는

 

추가적인 옵션

class ObjectAdmin(매개변수, 여러 개가 들어갈 수도 있다):

    필드들(optional)

    함수들(optional)

 

이렇게 구성된다. 

 

 

admin.ModelAdmin

장고 어드민 인터페이스의 구현체라고 한다. 

정확히 무슨 말인지는 모르겠다!

[이해하면 포스팅하기]

 

 

register

modelAdmin을 등록하기 위해서는 register 선언을 해 주어야 한다. 

admin 파일에 코드를 작성한 뒤, 작성한 내용을 관리자 페이지에 반영하기 위해서 필요한 작업이다. 

작성한 modelAdmin을 register으로 등록하는 방법은 두 가지가 있다. 

 

1. 메소드 사용하기

admin.site.register(모델, 모델 어드민 클래스)

class AuthorAdmin(admin.ModelAdmin):
    // code
    
admin.site.register(Author, AuthorAdmin)

 

2. 데코레이터(decorator) 사용하기

장고에서 @을 사용하여 추가적인 기능을 제공하는 것을 데코레이터(decorator)라고 한다. 

 

@admin.register(모델)

class 모델 어드민 클래스(admin.ModelAdmin):

    // 세부 코드

@admin.register(Author):
class AuthorAdmin(admin.ModelAdmin):
	// code

 

또한 하나의 어드민 클래스에서 여러 모델을 관리할 수도 있기 때문에, 여러 개의 모델을 입력할 수도 있다. 

 

@admin.register(모델1, 모델2, 모델3)

class 모델 어드민 클래스(admin.ModelAdmin):

    // 세부 코드

 

 

관리자 페이지가 다른 어플리케이션과 연결되는 원리

settings.pyINSTALLED_APPS 필드에는 기본값으로 django.contrib.admin이 추가되어 있다. 

이 클래스가 settings.py에 추가되어 있다면, 앱(어플리케이션, 서버)이 시작하자마자 django.contrib.admin 클래스의 모듈은 INSTALLED_APPS 안에 있는, admin을 사용하는 다른 앱에 import 된다. 

 

이게 가능한 이유는 django.contrib.admin의 autodiscover() 함수 때문이다. 

autodiscover() 메소드는서버가 시작하자마자 INSTALLED_APPS에 등록된 다른 앱에서 admin을 사용하는 모델을 찾고, 그 모델들을 관리자 사이트에 등록시킨다. 

 

autodiscover() 메소드는 서버 시작 시 모든 admin에 등록할 모델들을 자동으로 불러오지만, 관리자 페이지를 커스터마이징했을 때 일부 상황에서는 이 기능이 필요하지 않을 수 있다. 

 

autodiscover() 메소드를 사용하고 싶지 않다면, django.contrib.admin 클래스 하위에 있는 apps.SimpleAdminConfig 클래스를 사용해야 한다. 원래 django.contrib.admin은 apps.AdminConfig 메소드를 기본값으로 사용했었다.

 

즉 django.contrib.admin은 아무 옵션도 추가하지 않을 경우 기본값으로 django.contrib.admin.apps.AdminConfig 클래스를 사용해 왔던 것이다. 

그러나 autodiscover() 메소드를 사용하고 싶지 않다면 settings.py의 INSTALLED_APPS에 django.contrib.admin 을 지우고 django.contrib.admin.apps.SimpleAdminConfig를 추가하면 된다. 

 

 

ModelAdmin 인터페이스의 옵션들

ModelAdmin은 규모가 큰 인터페이스이고, 그만큼 커스터마이징을 위한 여러 옵션을 추가할 수 있다. 

옵션은 각 어드민 클래스의 필드 형식으로 지정하면 된다. 

 

1. actions

actions의 값으로는 함수들의 리스트를 입력한다. 

해당 어드민 클래스에서 사용할 수 있는 함수, 기능들을 나열할 수 있다. 

 

2. actions_on_top / actions_on_bottom

True나 False를 입력한다. 

actions 옵션으로 입력한 기능들을 페이지의 위에 표시할지, 아래에 표시할지를 지정한다. 

class ProjectAdmin(admin.ModelAdmin):
	actions_on_top = True

 

3. date_hierarchy

모델의 필드 중 DateField 또는 DateTimeField 타입인 필드 이름을 값으로 갖는다. 

해당 모델의 데이터를 정렬할 때 입력한 필드의 날짜 순서대로 정렬해 준다. 

역순으로 정렬하고 싶다면 필드 이름 앞에 - 을 붙이면 된다. 

class ProjectAdmin(admin.ModelAdmin):
	date_hierarchy = '-register_date'

 

4. empty_value_display

문자열을 값으로 받는다. 

두 가지 방법으로 사용할 수 있다. 

 

첫째로, 각 어드민 클래스의 필드 이름으로 empty_value_display를 사용해서 지정할 수 있다. 

해당 모델의 필드 중 빈 값(null 또는 "" 공백 문자열)이 있다면 그 값을 관리자 페이지에서 어떻게 표시할지를 지정한다. 

class UserAdmin(admin.ModelAdmin):
	empty_value_display = 'EMPTY'

 

둘째로, 데코레이터를 사용해서 각 필드값을 리턴하는 함수 위에 붙여서 사용할 수 있다. 

첫번째 방법에서는 해당 모델에 속한 모든 필드의 빈 값을 같게 나타내지만, 두 번째 방법을 사용하면 각 필드별로 빈 값을 다르게 표시할 수 있다. 

class UserAdmin(admin.ModelAdmin):
	list_display = {'id', 'view_username', 'view_userid'}

	@admin.display(empty_value="no name")
	def view_username(self, obj):
    	return obj.username
        
	@admin.display(empty_value="no id")
	def view_userid(self, obj):
		return obj.userid

 

5. exclude

필드 리스트를 값으로 받는다. 

제외하고 싶은 필드들이 있을 때, exclude의 값으로 입력한다. 

class UserAdmin(admin.ModelAdmin):
	exclude = ['birth-date', 'age']
	// birth-date, age 필드를 제외한 모든 필드가 관리자 페이지에 나타남

 

6. fields

필드 이름 튜플을 값으로 받는다. 

데이터를 수정(change)이나 추가(add)하는 페이지에서 fields의 값에 포함된 필드들만 나타나게 할 수 있다. 

serializer.py에서 read-only로 지정된 필드들만 fields 리스트에 포함될 수 있다. 

더 세부적인 작업을 하고 싶으면 fieldsets 옵션을 사용하자. 

# models.py
class Homework(models.Model):
	title = models.CharField('제목')
	content = models.TextField()
	teacher = models.ChoiceField(choices=TEACHER_LIST)
	submission_date = models.DateTimeField()

# admin.py
class HomeworkAdmin(admin.ModelAdmin):
	fields = ('title', 'content')

 

위 예시의 경우, 데이터를 추가 및 수정하는 페이지에서는 title과 content 필드에 대해서만 수정 및 추가 작업을 할 수 있다. 

또한, fields 튜플 안에서 괄호()를 한번 더 사용하면, fields 튜플 안의 필드들을 한 줄로 나타낼 수 있다. 

 

7. fieldsets

fields와 기본적인 역할은 같고, 튜플을 원소로 갖는 튜플 리스트(two-tuple)를 값으로 받는다. 처음 관리자 페이지에서 보는 카테고리 화면이 아니라, 데이터를 추가나 수정하는 페이지에서 선택한 필드를 그룹으로 묶어서 나타내는 데 사용한다. 

fields 옵션에서는 필드 그룹이 하나만 있었다면, fieldsets 옵션에서는 하나의 모델에 대해서도 여러 필드 그룹을 만들 수 있다. 

여러 개의 그룹을 만들고 싶다면 fieldsets 안에서 튜플을 여러 개 만들면 된다. 각 튜플은 "옵션"과 {} 딕셔너리로 이루어진다. 

 

이런 식으로 만들면 된다. 

 

fieldsets = (

    ("그룹_1의 이름", {

        "fields": ('그룹_1에 들어갈 필드_1', '그룹_1에 들어갈 필드_2')

    }),

    ("그룹_2의 이름", {

        "fields": ('그룹_2에 들어갈 필드_1', '그룹_2에 들어갈 필드_2'), 

    })

)

# models.py
class Course(models.Model):
	student_name = models.CharField()
	lecturer_1 = models.ChoiceField(choices=LECTURER_LIST)
	course_1 = models.ChoiceField(choices=LECTURER_LIST)
	lecturer_2 = models.ChoiceField(choices=LECTURER_LIST)
	course_2 = models.ChoiceField(choices=LECTURER_LIST)
	lecturer_3 = models.ChoiceField(choices=LECTURER_LIST)
	course_3 = models.ChoiceField(choices=LECTURER_LIST)
    
# admin.py
class CourseAdmin(admin.ModelAdmin):
	fieldsets = (
		("강의 1", {"fields": (('lecturer_1', 'course_1'))}),
		// 그룹 이름을 '강의 1'로 설정
		// 강의 1에 해당하는 필드들을 개별 그룹으로 표시
		// 필드들을 한 줄에 표시
        
		("강의 2", {"fields": ('lecturer_2', 'course_2')})
		// 그룹 이름을 '강의 2'로 설정
		// 강의 2에 해당하는 필드들을 개별 그룹으로 표시
		// 각 필드는 한 줄을 차지함
    )

 

또한 fieldsets 내부의 딕셔너리의 값으로 "fields" 뿐만 아니라 다른 값을 추가로 사용할 수도 있다. 

대표적으로는 classes, description 등이 있다. 

 

1) classes

해당 fieldset에 CSS 속성을 적용할 때 사용한다. 

class CourseAdmin(admin.ModelAdmin):
	fieldsets = (
		(None, {
        "fields": (('lecturer_1', 'course_1')),
        "classes": ('wide', 'extrapretty')
        }),
    )

 

2) description

각 fieldset 위에 추가 텍스트를 넣을 때 사용한다. 

 

또한 fields나 fieldsets 옵션을 따로 명시하지 않았다면, 장고에서는 기본값으로 AutoField가 아니고 editable=True로 된 필드들만 관리자 페이지에 포함시킨다. 

 

 

fieldsets, list_display의 차이점

헷갈리는 부분이라 적어보았다. 

fields와 fieldsets는 처음 관리자 페이지에서 모델명을 누르면 나오는 조회 페이지가 아니라, 조회 페이지에서 개별 데이터를 누르면 나오는 추가 및 수정 페이지에서 어떤 필드를 표시할지를 결정한다. 

반면 list_display는 관리자 페이지 시작 화면에서 모델명을 누르면 나오는 조회 페이지에서 어떤 필드를 표시할지를 결정한다. 

 

8. filter_horizontal & filter_vertical

필드 이름 튜플을 값으로 받으며, ManyToManyField(다대다 필드) 에서만 작동한다. 

fieldsets과 마찬가지로 조회 페이지가 아니라 추가 및 수정 페이지에서 작동한다. 

many-to-many field 특성상 선택하는 가짓수가 많을 때는 다루기 어려울 수 있기 때문에, 간단한 인터페이스를 사용해서 데이터를 쉽게 추가 및 수정할 수 있게 했다. 

 

filter_horizontal의 경우 선택되지 않은 가짓수(옵션)이 왼쪽, 선택된 옵션이 오른쪽 박스에 나타난다. 

filter_vertical의 경우 선택되지 않은 옵션이 위쪽, 선택된 옵션이 아래쪽 박스에 나타난다. 

 

9. form

관리자 페이지에서 모델뿐만 아니라 폼 데이터를 추가 및 수정할 때 사용한다. 

# forms.py
class CarForm(forms.ModelForm):
	
    class Meta:
		model = Car
 		exclude = ['engine oil']
        
# admin.py
class CarAdmin(admin.ModelAdmin):
	form = CarForm

 

위의 경우, admin-form-model이 연결되어 데이터를 수정 및 변경할 수 있다. 

 

 

참고한 포스트

Admin actions | Django documentation | Django (djangoproject.com)

The Django admin site | Django documentation | Django (djangoproject.com)

장고 마스터하기 - 5장 - 김땡땡's blog (yonghyunlee.gitlab.io)

 

+ Recent posts