본문 바로가기
Web/Django

[Django] 커스텀 Admin 페이지

by DUSTIN KANG 2024. 1. 10.

Django는 사이트  편리하게 모델을 관리할 수 있도록 관리자 기능 페이지를 기본적으로 제공한다.

오늘은 Admin 페이지를 활용하는 방법에 대해 알아보려고 한다.

 

BASE_URL/admin/

Admin 페이지 접속하기

우선, Admin 페이지에 접속하려면, `superuser`(관리자)를 생성해야 한다.

다음 `createsuperuser` 명령어를 입력해서 Admin 페이지에 접근한다.

python manage.py createsuperuser
사용자 이름(Username) : admin
이메일 주소: 
Password: 
Password (again): 
Superuser created successfully.

 

초기에 관리자 사이트에 들어가게 되면 user와 Groups만 볼 수 있다. 사전에 작성한 모델을 올려보도록 하자.

  • 사전에 프로젝트와 앱을 생성하고 모델을 정의했다.
  • makemigration, migrate으로 마이그레이션을 했다.
더보기

커스텀한 User 모델, 그룹 표시하기

admin.site.register(UserModel, UserAdmin)
admin.site.unregister(Group)

 

커스텀 User 모델 생성하기 포스트↗

커스터마이징 옵션

해당 앱의 `admin.py` 파일에 모델을 관리자 페이지에 등록할 수 있다. 커스텀이 필요한 경우에는 데코레이터를 이용해 클래스를 작성한다. 

from django.contrib import admin
from gs25.models import Market, Product
# Register your models here.

# 커스텀이 필요하지 않는 경우
admin.site.register(Market)
# admin.site.unregister(Market)

# 커스텀이 필요한 경우
@admin.register(Product)
class Product(admin.ModelAdmin):

    list_display = ('name', 'price',)
    list_display_links = ('name',)
    ordering = ('name') # 정렬 순서를 정한다.

 

list_display

Admin 사이트에 보여질 필드를 정의하는 옵션이다.

  • `ManytoManyField`는 지원하지 않는다.
  • 리스트나 튜플 형태로 작성한다.
  • `list_display_links` 옵션은 링크 기능을 추가할 필드를 지정하는 옵션이다. 해당 링크를 클릭하면 정보를 수정할 수 있다.

 

다음과 같이 함수를 작성해서 관리자 페이지에 보여질 값도 커스터마이징할 수 있다.

@admin.register(Product)
class Product(admin.ModelAdmin):

    list_display = ('name', 'price', 'market_count')
    
	def market_count(self, product):
        return product.market.count()

 

 

readonly_fields

수정이 불가능하고 읽기만 가능한 필드를 표시 할 수 있다.

	list_display = ('name', 'price', 'market_count',"created_at", "updated_at",)
	readonly_fields = ("created_at", "updated_at",)

list_filter

Admin 사이트에 보여질 필드를 필터링하는 옵션이다.

`django-admin-rangefilter`를 설치하면 날짜 범위를 지정하여 필터링할 수 있다.

@admin.register(Product)
class Product(admin.ModelAdmin):

    list_display = ('name', 'price',)
    list_display_links = ('name',)
    list_filter = ('group', 'expire_date') # Datetime 필드는 날짜 옵션이 제공된다.

 

커스텀 필터링

Admin 사이트에 보여질 필드를 필터링을 커스터마이징할 수 있다.

예를 들어서, 해당 제품 중에 오뚜기 제품만 필터링해서 Product를 출력하는 필터 클래스를 작성해 필터링에 추가했다.

커스텀 필터링은 `SimpleListFilter`를 상속받아 filter 요소를 추가할 수 있다. 반드시, `title`, `parameter_name` 변수와 `lookups` `queryset`  메서드가 있어야 한다.

  • title : 필터링 이름
  • parameter)name : 필터에 사용할 컬럼 이름 (URL 쿼리 스트링에 사용된다.)
  • lookups : 필터에 보이게되는 것을 작성하는 메서드
  • queryset : 특정 필터를 클릭했을 때 동작 구현 메서드 
class OddukiFilter(admin.SimpleListFilter):
    title = "오뚜기 제품 필터링"
    parameter_name = "Odduki"

    def lookups(self, request, model_admin):
        return [
            ("오뚜기", "오뚜기제품"), # (url쿼리, 페이지에 보여지는 이름)
        ]
    
    def queryset(self, request, product):
        word = self.value() # url 쿼리를 받는다.
        if word:
            return product.filter(name__contains=word)
        return product
        

@admin.register(Product)    
class Product(admin.ModelAdmin):

    list_display = ('name', 'price', 'market_count')
    list_display_links = ('name',)
    list_filter = ('group', 'expire_date','market', OddukiFilter)  # 추가
    
 # product/?Odduki=오뚜기

search_fields

검색어를 입력하면 그 문자열과 맞는 필드를 찾는 옵션이다. 찾는 방식은 아래처럼 다양하게 존재하니 알맞게 선택하여 검색하면 된다.

  •  ^ : 검색어로 시작하는 경우
  • = : 해당 문자열이 정확히 일치하는 경우(갯수 판단할 때 사용)
  • 아무것도 없음 : 해당 문자열이 포함되는 경우
  • @ : 단어나 구문을 검색할 때 사용한다.
  • foreginkey__related_fieldname  : ForeignKey 혹은 ManytoMany 필드를 조회할 때 사용한다.
# 커스텀이 필요한 경우
@admin.register(Product)
class Product(admin.ModelAdmin):

    list_display = ('name', 'price',)
    list_display_links = ('name',)
    list_filter = ('group', 'expire_date')
    search_fields = ('name', '=price',)

 

fieldsets

admin 페이지에서 데이터를 추가하거나 수정할 때 입력폼을 변경할 수 있다.

    # 수정할 때 사용하는 입력 폼
    fieldsets = (
        ("상품 정보", {'fields': ('name', 'price', 'group', 'expire_date')}),
        ("마켓 관련", {'fields': ('market',)}),
    )

    # 추가할 때 사용하는 입력폼
    add_fieldsets = (
        (None, {
            'classes': ('wide',), # 넓은 폼 스타일을 적용한다.
            'fields': ('name','price', 'group', 'expire_date', 'market')
            }
         ),
         
    filter_horizontal = ('market',)

 

 

Actions

Admin 페이지에서는 CRUD를 편리한 인터페이스를 이용하여 수행할 수 있다. 

그 중에서 데이터를 삭제할 때 아래 액션 탭을 이용해 제거할 수 있다. 제거 외에도 커스터마이징해서 액션을 추가할 수 있다.

 

 

아래는 Action을 추가하는 함수를 정의했다. 반드시 `model_admin` 클래스에 action을 추가해야 한다.

  • model_admin : 모델 Admin 클래스를 의미한다. 클래스 내부에 작성할 경우 `self`로 사용하면 된다.
  • request : 요청을 나타내는 부분이다.
  • Queryset : 사용자가 선택한 객체이다. ✅
@admin.action(description="판매 불가 제품으로 변경합니다.")
def bannedsale(model_admin, request, products):
    # model_admin, request, Queryset

    # bannedsale.short_description = "판매 불가 제품으로 변경합니다."
    for product in products.all():
        product.state = '판매 중지'
        product.save()
    
    messages.warning(request, '판매 중지 상품으로 변경되었습니다.')
    

@admin.register(Product)    
class Product(admin.ModelAdmin):

    actions = (bannedsale,)

 

 

Meta 내부 클래스

`models.py` 내부 Meta 클래스에서 관리자 화면에 보여지는 객체 이름을 단수형, 복수형에 따라 다르게 표시할 수 있다.

    class Meta:
        verbose_name = "상품" # 단수
        verbose_name_plural = "상품들" # 복수
        db_table = 'products' # 데이터베이스 테이블 이름을 변경 (반드시 마이그레이션 필수)
        ordering = ['-name'] # 최신순(-)으로 admin 페이지 내 데이터를 정렬한다.

 

모델 명 뿐만 아니라 관리자 페이지에 표시되는 필드 명 또한 수정이 가능하다.

    group = models.CharField(max_length=20, choices=GroupsChoice.choices,
            help_text="해당 제품은 신선한 상품인가요?", verbose_name="상품 타입")

 


Admin styling

이번엔 어드민 페이지를 스타일링하는 방법이다. Django에는 스타일링 관련 다른 패키지들도 존재하니 Django Packages 사이트를 참조하면 된다. 저는 `Django-Grappelli`가 사용횟수가 많고 지금까지도 업데이트 되었기 때문에 이 패키지를 사용해보았습니다. 

 

 


☕️ 마치며

오늘도 저의 포스트를 읽어주셔서 감사합니다. 

설명이 부족하거나 이해하기 어렵거나 잘못된 부분이 있으면 부담없이 댓글로 남겨주시면 감사하겠습니다.