Framework/Django

[Dj] 장고 관리자(Admin) 페이지 꾸미는 방법

QUERY 2021. 8. 19. 21:49

 


장고-로고
장고-로고


장고에서 기본적으로 제공하는 기능들(e.g. filters, list, displays and more)을 활용해서 관리자(admin) 페이지를 꾸미는 방법에 대해 알아보겠습니다. 이는 관리자 페이지에 모델이 표시되는 방법이라든지, 모델의 배열 방향이라든지, 여러 개의 모델들을 한 화면에서 설정할 수 있는 방법이라든지 등의 기능적인 측면에 초점을 맞춘 꾸미기입니다. 제3의 패키지를 사용해 관리자 페이지를 화려하게 꾸미는 방법은 다른 포스트에서 다시 다뤄보도록 하겠습니다.

 

통상적으로 장고 프로젝트에 앱을 설치하면, 설치된 앱마나 models.py에 class 형태의 모델들이 존재하고, 이 모델들을 장고 관리자 페이지에서 확인하고 관리하기 위해 admin.py에 각각의 모델들을 등록해줍니다. 이해를 돕기 위해 예를 들어보겠습니다. 멤버십으로 운영되는 온라인 강의 플랫폼을 만든다고 가정해보겠습니다. courses라는 앱을 만들었고, 해당 앱의 models.py에는 Course 모델과 Lesson 모델이 존재합니다.

>>> courses/models.py

from django.db import models
from django.urls import reverse
from memberships.models import Membership

class Course(models.Model):
        slug = models.SlugField()
        title = models.CharField(max_length=120)
        description = models.TextField()
        allowed_memberships = models.ManyToManyField(Membership)

        def __str__(self):
                return self.title

        def get_absolute_url(self):
                return reverse('courses:detail', kwargs={'slug': self.slug})

        @property
        def lessons(self):
                return self.lesson_set.all().order_by('position')

class Lesson(models.Model):
        slug = models.SlugField()
        title = models.CharField(max_length=120)
        course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True)
        position = models.IntegerField()
        video_url = models.CharField(max_length=200)
        thumbnail = models.ImageField()

        def __str__(self):
                return self.title

        def get_absolute_url(self):
                return reverse('courses:lesson-detail',
                                        kwargs={
                                                'course_slug': self.course.slug,
                                                'lesson_slug': self.slug
                                         })

보통 Course 모델과 Lesson 모델을 관리자 페이지에 등록하기 위해, admin.py 파일에 각각의 모델들을 등록시켜주는 절차를 거칩니다.

>>> courses/admin.py

from django.contrib import admin
from .models import Course, Lesson

admin.site.register(Course)
admin.site.register(Lesson)

모델들-장고-관리자-페이지에-삽입
모델들-장고-관리자-페이지에-삽입

그러면 위 사진과 같이 해당 모델들을 관리할 수 있도록 관리자 페이지에 나타나게 됩니다.

장고-관리자-페이지-course-모델-추가창-모습
장고-관리자-페이지에서-course-모델에-추가창
장고-관리자-페이지-lesson-모델-추가창-모습
장고-관리자-페이지에서-lesson-모델에-추가창

각각 Course 추가와 Lesson 추가를 했을 때의 모습입니다. 만약, 현재와 같은 화면에 만족한다면, admin.site.register(모델명) 만으로도 충분합니다. 하지만 지금 같은 경우, 새롭게 코스(course)를 생성하고, 또 그에 따른 레슨(lesson)들이 추가로 생성할 때마다 각각의 페이지를 오가며 따로따로 추가/수정해줘야 하는 번거로움을 감내해야만 합니다. 그런데 이 두 개의 화면을 하나로 합쳐서 관리할 수 있는 방법이 있습니다. 바로 from django.contrib import admin으로부터 상속받는 ModelAdmin을 활용하는 방법입니다. 그럼 하나의 코스(course)를 새롭게 추가할 때, 그에 따른 레슨(lesson)들도 동시에 추가/수정할 수 있기 때문에 훨씬 관리하기가 수월해집니다.

 

먼저, ModelAdmin으로 admin.site.register(Course)와 같은 결과를 가져오는 class 함수를 만들어보겠습니다.

>>> courses/admin.py

from django.contrib import admin
from .models import Course, Lesson


class CourseAdmin(admin.ModelAdmin):
        pass

admin.site.register(Course, CourseAdmin)

참고로 이때, admin.site.register()가 아니라, 데코레이터를 사용해서 등록하는 방법도 있습니다. @admin.register()를 사용해도 관리자 페이지에 표시되는 결과는 모두 동일합니다.

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
        pass

 


 


 

1. fields

다시 본론으로 돌아가서, ModelAdmin으로 class 함수를 만들 경우, 관리자에서 관리하고자 하는 모델의 세부 필드(fields)를 설정해줄 수 있습니다. 예를 들면,

class CourseAdmin(admin.ModelAdmin):
        fields = (
                'slug',
                'title',
                'description',
                'allowed_memberships'
)

admin.site.register(Course, CourseAdmin)

위와 같이 fields의 항목들을 세부적으로 선택해줄 수 있습니다. 물론 여기에 나오는 항목들은 모두 courses/models.py에서 Course 모델에 정의된 항목들이어야만 합니다.

 


참고. add_form

참고로, 위 항목들 이외에 추가적으로 폼(form)을 덮어쓸 수 있는 방법도 있습니다. courses/forms.py에서 새로운 폼 양식을 작성한 후, add_form을 이용하는 방법입니다.

class CourseAdmin(admin.ModelAdmin):
        add_form = 새로 생성한 폼

 


2. fieldsets

fields 대신 fieldsets을 이용해서 모델의 인스턴스들을 추가/수정할 수 있습니다.

class CourseAdmin(admin.ModelAdmin):
        fieldsets = (
                (None, {
                        'fields': (
                                'slug',
                                'title',
                                'description',
                                'allowed_memberships',
                        )
                }),
        )

 


3. list_display

list_display로 장고 관리자 페이지의 리스트 디스플레이에 변화를 줄 수도 있습니다. (단, ManyToManyField는 리스트 디스플레이에 추가할 수 없습니다. 우리 예시의 경우, allowed_memberships가 해당됩니다.)

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description')

course-모델-스트링메소드로-셀프.타이틀만-표시할-경우
__str__메소드로-타이틀만-표시된-경우 
리스트-디스플레이로-타이틀-슬러그-설명까지-표시할-경우
list_display로-타이틀-슬러그-설명까지-표시한-경우

courses/models.py에서 Course 모델을 정의할 때 사용했던 def __str__() 함수의 self.title로 인해서 장고 관리자 페이지의 리스트 디스플레이에 타이틀만 뜨게끔 설정돼 있었던 게, list_display로 타이틀, 슬러그, 디스크립션을 추가해주자, 관리자 페이지의 리스트 디스플레이에 3가지 섹션이 구분 지어 보이는 것을 확인할 수 있습니다.  단순히 제목(title)만 보이는 것보다, 원하는 세부 사항들을 한눈에 확인할 수 있기 때문에 많은 데이터를 관리할 때 특히 편리합니다.

 


참고. 커스터마이징

이때, 직접 원하는 섹션을 만드는 것도 가능합니다.

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        fieldsets = (
                (None, {
                        'fields': (
                                'slug',
                                'title',
                                'description',
                                'allowed_memberships',
                        )
                }),
        )

        def combine_title_and_slug(self, obj):
                return "{} - {}".format(obj.title, obj.slug)

직접-커스터마이징한-섹션을-리스트-디스플레이에-추가
직접-커스터마이징한-섹션을-리스트-디스플레이에-추가

제목과 슬러그를 합친 함수를 만들어 리스트 디스플레이에 등록해주면, 관리자 페이지에 "제목 - 슬러그"를 함께 표시해주는 섹션이 추가된 것을 확인할 수 있습니다. 사용자가 원하는 형태로 데이터들을 분류해서 표시할 수 있어 알아두면 요긴하게 사용할 수 있습니다.

 


4. list_display_links

이밖에, list_display_links를 사용할 수도 있습니다. 말 그대로 리스트 디스플레이에 표시된 내용들을 클릭하면 그 세부사항(해당 인스턴스)을 확인할 수 있도록 링크로 연결시켜주는 기능을 의미합니다. list_display_links로 title과 slug를 추가한다면, 관리자 페이지에서 슬러그 인스턴스로의 링크가 연결된 것을 확인할 수 있습니다.

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'slug')

타이틀과-슬러그에-리스트-디스플레이-링크-연결
타이틀과-슬러그에-리스트-디스플레이-링크-연결

 


5. list_editable

관리자 창에서 바로 수정할 수 있도록 해주는 list_editable 기능도 있습니다. (단, list_editable과 list_display_links의 인자가 겹치게 설정할 순 없습니다.)

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'combine_title_and_slug')
        list_editable = ('slug')

장고-관리자-페이지의-리스트-디스플레이에-list-editable-적용된-모습
list editable 적용한 모습

 


 


 

6. list_filter

관리자 페이지 우측에 필터 섹션을 따로 만들 수 있습니다. 

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'combine_title_and_slug')
        list_editable = ('slug')
        list_filter = ('title', 'slug')

장고-관리자-페이지의-리스트-디스플레이-우측에-list-filter-적용돼-추가된-타이틀-필터와-슬러그-필터
리스트 필터 적용한 모습

단, 섹션의 종류가 한정적일 때 유용하게 사용할 수 있습니다. 만약 위 예시와 달리, 타이틀이 여러 개고, 슬러그가 여러 개일 경우엔, 필터의 길이가 길어져서 그 효용이 떨어지기 때문입니다.

 


7. search_fields

리스트 디스플레이에 검색 영역을 추가하고자 할 때 사용할 수 있습니다.

class CourseAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'combine_title_and_slug')
        list_editable = ('slug')
        list_filter = ('title', 'slug')
        search_fields = ('title', 'slug')

장고-관리자-페이지의-리스트-디스플레이에-추가된-검색창
리스트 디스플레이에 추가된 검색창

 


8. inlines

이제, Course 모델 관리 페이지에 Lesson 모델 관리 페이지를 추가하는 방법에 대해 알아보겠습니다. 이번에도 from django.contrib import admin에서 상속받은 InLineModelAdmin에 대해 알아보겠습니다.

class InLineLesson(admin.StackedInline):
        model = Lesson
        extra = 1

class CourseAdmin(admin.ModelAdmin):
        inlines = [InLineLesson]
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'combine_title_and_slug')
        list_editable = ('slug')
        list_filter = ('title', 'slug')
        search_fields = ('title', 'slug')

 

8-1. StackedInline

이때, admin.StackedInline 대신 admin.TabularInline을 사용할 수도 있는데, 이는 정렬되는 방식에 차이가 있습니다. StackedInline은 세로로 길게 나열되는데 반해, TabularInline의 경우, 가로로 길게 나열되는 특징이 있습니다.

stackedinline을-사용한-경우
stackedinline을 사용한 경우

8-2. TabularInline

tabularinline을-사용한-경우
tabularinline을 사용한 경우

 


이제까지 courses/admin.py에 추가한 모든 코드들입니다.

>>> courses/admin.py

from django.contrib import admin
from .models import Course, Lesson


class InLineLesson(admin.StackedInline):
        model = Lesson
        extra = 1


class CourseAdmin(admin.ModelAdmin):
        inlines = [InLineLesson]
        list_display = ('title', 'slug', 'description', 'combine_title_and_slug')
        list_display_links = ('title', 'combine_title_and_slug')
        list_editable = ('slug')
        list_filter = ('title', 'slug')
        search_fields = ('title', 'slug')
        fieldsets = (
                (None, {
                        'fields': (
                                'slug',
                                'title',
                                'description',
                                'allowed_memberships',
                        )
                }),
        )

        def combine_title_and_slug(self, obj):
                return "{} - {}".format(obj.title, obj.slug)

admin.site.register(Course, CourseAdmin)

지금까지 추가적인 패키지 설치 없이, 장고에 기본적으로 내장돼 있는 기능들을 사용해 장고 관리자 페이지를 꾸미는 방법에 대해 알아보았습니다. 이밖에도 사용할 수 있는 다양한 기능들이 장고에 내장돼 있습니다. 보다 자세한 기능과 활용방법에 대해 알아보고 싶으시다면, 장고 공식 홈페이지 들어가시면 확인해보실 수 있습니다.

https://docs.djangoproject.com/en/2.1/ref/contrib/admin/ 

 

The Django admin site | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com