Django admin custom (1) - 기본적인 admin form custom & simple custom template

정현우·2021년 10월 22일
4

Django Basic to Advanced

목록 보기
11/37
post-thumbnail

튜토리얼 이어서

  • 7장을 보고 8장을 이어가길 바란다. 공식 문서 튜토리얼에 내 입맛과 부족한 정보를 담아서 정리하는 것에 가깝다.

Django의 강력한 장점인 admin page 자동 생성. 그리고 form을 커스텀을 정해진 규칙 내에서 확실하게 있다. 또한 style (look&feel)또한 틀안에서 가능하다. 그 부분을 어떻게 해야할지 살펴보자!

관리자 폼 커스터마이징

  • Question 모델을 admin.site.register(Question)에 등록함으로써, Django는 디폴트 폼 표현을 구성 할 수 있었습니다. 관리 폼이 보이고 작동하는 방법을 커스터마이징하려는 경우가 있습니다. 객체를 등록 할 때 Django에 원하는 옵션을 알려주면 커스터마이징 할 수 있습니다.

filed 설정

  • 수정(또는 등록) 폼의 필드를 재정렬하여 이것이 작동하는 법을 보겠습니다. admin.site.register(Question) 줄을 다음과 같이 바꾸세요!
# polls/admin.py
from django.contrib import admin

# Register your models here.
from .models import Choice, Question

admin.site.register(Choice)

class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)
  • 모델의 관리자 옵션을 변경해야 할 때마다 이 패턴 – 모델 어드민 클래스를 만든 다음, admin.site.register()에 두 번째 인수로 전달합니다!

  • Qustion text가 Date 설정하는 것 보다 하단에 위치하게 된다. 우리가 설정한 fields 값에서 배열의 순서를 생각하면 된다.

  • 단지 2개의 필드만으로는 인상적이지는 않지만, 수십 개의 필드가 있는 관리 폼의 경우에는 직관적인 순서을 선택하는 것이 사용 편리성의 중요한 부분입니다.

  • 수십 개의 필드가 있는 폼에 관해서는 폼을 fieldset으로 분할하는 것이 좋습니다.

# polls/admin.py
... #생략
class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Question, QuestionAdmin)
... #생략

  • (filedname, value) 형태로 fieldsets를 설정하면서, filedname으로 설정한 값으러 표시가 된다.

관련된 객체 추가

  • 즉 관계를 가지고 있는 model을 추가하는 것!

  • OK, 우리는 Question 관리자 페이지를 가지고 있습니다. 그러나, Question은 여러 개의 Choice들을 가지고 있음에도, admin 페이지는 선택 사항을 표시하지 않습니다.

  • 지금과 같이 그냥 admin.site.register를 통해 model을 등록을 해도 괜찮지만, Django는 ForeignKey가 admin에서 <select>로 표현되어야 함을 알고 있습니다. 우리의 경우, 지금은 단 하나의 질문만이 존재합니다.

  • 또한 《Question》 옆의 《Add Another》 링크를 주목하세요. ForeignKey 관계를 가진 모든 객체는 저 링크가 붙습니다. 《Add Another》를 클릭하면 《Add question》 폼이 있는 팝업 창이 나타납니다. 해당 창에 질문을 추가하고 《Save》를 클릭하면 장고는 질문을 데이터베이스에 저장하고, 동적으로 이를 선택된 항목으로 당신이 보고있는 《Add choice》 폼에 추가합니다.

  • 그러나 실제로 이것은 Choice 객체를 시스템에 추가하는 비효율적인 방법입니다. Question 객체를 생성할 때 여러 개의 Choices를 직접 추가할 수 있다면 더 좋을 것입니다. 그것을 만들어 봅시다.

# 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)


  • 이 화면은 다음과 같이 작동합니다. 관련된 선택 사항을 위한 슬롯이 세 개 있으며 - extra로 지정됨 – 이미 생성된 객체의 《Change》 페이지의 경우에도 빈 세 개의 슬롯이 생깁니다.

  • 하지만 화면에서 너무 많은 부분을 차지한다. For that reason, Django offers a tabular way of displaying inline related objects. To use it, change the ChoiceInline declaration.

class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 3
  • StackedInline 대신에 TabularInline을 사용하면, 관련된 객체는 좀 더 조밀하고 테이블 기반 형식으로 표시됩니다!

  • 참고로 《Delete?》 열은 《Add Another Choice》 버튼으로 추가된 행과 이미 저장된 행을 삭제하는데 사용합니다.

관리자 변경 목록 커스텀

  • 시스템의 모든 질문을 표시하는 《변경 목록》 페이지를 약간 조정해봅시다.

  • 기본적으로 Django는 각 객체의 str()을 표시합니다. 그러나 개별 필드를 표시 할 수 있는 경우 가끔 도움이 될 수 있습니다.

  • list_display = ('question_text', 'pub_date') 이렇게 하려면 list_display admin 옵션을 사용합니다. 이 옵션은 객체의 변경 목록 페이지에서 열로 표시 할 필드 이름들의 튜플입니다.


  • 또한 was_published_recently 함수를 포함시키는 것도 좋은 방법입니다!! QuestionAdmin을 아래와 같이 바꿔봅시다!
class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date', 'was_published_recently')
    
# was_published_recently 함수는 Model에서 Question class의 메서드(내부 함수)이다. return값이 boolean

  • 각 단계들이 admin페이지에서 어떻게 list를 표현하는지 차이점을 보자! list_display에 대한 상세내용은 공식문서에!

  • was_published_recently 헤더의 경우를 제외하고 그 값으로 정렬하기 위해 열 머리글을 클릭 할 수 있습니다. 왜냐하면 임의의 메서드의 출력에 의한 정렬은 지원되지 않기 때문입니다. 또한 was_published_recently에 대한 열 머리글은 기본적으로 메서드 이름 (밑줄을 공백으로 대체)이며 각 줄에는 출력의 문자열 표현이 포함되어 있습니다.

... # 생략
from django.contrib import admin
... # 생략

# Create your models here.
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    
    @admin.display(
        boolean=True,
        ordering='pub_date',
        description='Published recently?',
    )

    def __str__(self):
        return self.question_text
      
    # def was_published_recently(self):
    #     return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # 위 코드에서 미래에 있다면 False를 반환 하게 버그 수정
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

... # 생략

# polls/admin.py
... # 생략
class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date', 'was_published_recently')
    list_filter = ['pub_date']
... # 생략
  • @admin.display 어노테이션으로 설정해주고, list_filter를 추가해주면, 해당 모델의 리스트를 표현할때 filter 값이 생긴다.

  • 이제 검색기능을 추가해보자! DB model의 어떤 filed(컬럼)값을 기준으로 검색을 하게 할까를 먼저 고민하고, search_fileds만 추가하면 된다. search_fields = ['question_text']을 admin -> QuestionAdmin Class에 추가만 하면 된다.

  • 그러면 변경 목록 맨 위에 검색 창이 추가됩니다. 누군가가 검색어를 입력하면, 장고는 question_text 필드를 검색합니다. 당신이 원하는 만큼의 필드를 사용할 수 있습니다 – 그것은 내부적으로 LIKE 쿼리를 사용하기 때문에 검색 필드의 수를 적당한 수로 제한하면 데이터베이스가 검색을 더 쉽게 할 수 있습니다.

  • 이제 변경 목록이 자동 페이징 기능을 제공한다는 점을 기억하십시오. 기본값은 페이지 당 100 개의 항목을 표시하는 것입니다. 변경 목록 페이지내이션, 검색 상자, 필터, 날짜-계층구조, 그리고 컬럼-헤더-정렬 모두 함께 작동합니다.


관리자 Look&feel 커스터마이징

  • 관리자에서 관리하는 model, 표현 형태 등의 폼만 수정하는 것이 아니라, UI/UX적인 요소도 커스텀이 가능하다.

  • 명백히, 모든 관리자 페이지 상단에 《Django administration》이 있다는 것은 우스꽝스럽습니다. 이건 그저 자리를 채워넣기 위한 문자열입니다.

admin templates

  • 프로젝트 디렉토리에 (app디렉토리가 아닌, manage.py가 있는) templates 디렉토리를 만들어 추가하자. 템플릿은 장고가 액세스 할 수있는 파일 시스템 어디에서나 사용할 수 있습니다. (Django는 서버가 실행되는 사용자로 실행됩니다.) 그러나 프로젝트 내에 템플릿을 유지하는 것은 따라야 할 좋은 규칙입니다.

  • 설정 파일 (mysite/settings.py를 기억하세요)을 열고 DIRS 옵션을 TEMPLATES 설정에 추가하십시오!

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'], # 이 부분이 admin 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 템플릿을 로드 할 때 검사 할 파일 시스템 디렉토리 목록입니다. 바로 검색 경로입니다.

  • 정적 파일과 마찬가지로, 하나의 커다란 템플릿 디렉토리에 모든 템플릿을 함께 넣을 수 있습니다. 그렇게 해도 완벽하게 잘 작동할 것입니다. 그러나, 특정 애플리케이션에 속한 템플릿은 프로젝트(templates) 가 아닌 해당 애플리케이션의 템플릿 디렉토리(예: polls/templates)에 있어야 합니다. 우리는 왜 우리가 이렇게 해야하는 지에 대한 더 자세한 내용을 reusable apps tutorial 에서 논의할 것입니다. -> 재사용 가능성, 캡슐화 등의 효율 위해!

  • 이제 templates 디렉토리에 admin이라는 디렉토리를 만들고 장고 소스 코드 디렉토리(django/contrib/admin/templates) 에 기본 관리자 템플릿 디렉토리 안에 있는 admin/base_site.html 템플릿을 방금 만든 디렉토리로 복사합니다.

  • 위 경로에 있는 이미지를, 아래 이미지 경로로 가져오기! -> 코어에 접근해서 편집이 가능하다. 하지만 core(original)을 건들이는 만큼, 원복이 힘들어지고, 그런 접근법은 절대 옳은 방법이 아니라고 생각한다.

  • 즉 장고 Framework가 포함하고 있는 template 소스코드를 들고와야 한다. 근데 경로가 어딘지 모르겠다면 python -c "import django; print(django.__path__)"를 이용하자!

{% extends "admin/base.html" %}

{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site
admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}
  • Then, edit the file and replace {{ site_header|default:_('Django administration') }} (including the curly braces) with your own site’s name as you see fit. You should end up with a section of code like:

  • 이 방법을 사용하여 템플릿을 재정의하는 방법을 학습합니다. 실제 프로젝트에서는 아마 django.contrib.admin.AdminSite.site_header 속성을 사용하여 이 개별 커스터마이징을 보다 쉽게 만들 수 있습니다.

  • 이 템플릿 파일에는 {% block branding %}및 {{title}}과 같은 텍스트가 많이 포함되어 있습니다. {%와 {{태그들은 장고의 템플릿 언어의 일부입니다. Django가 admin/base_site.html을 렌더링 할 때, 이 템플릿 언어는 튜토리얼 3장에서 보았 듯이 최종 HTML 페이지를 생성하기 위해 평가 될 것입니다.

그럼 django는 어떻게 default template을 찾을까

  • 그러나 DIRS가 기본설정으로 비어 있다면, 장고는 기본 관리자 템플릿을 어떻게 찾을까요? 그 해답은 APP_DIRS 설정이 True로 설정되어 있기 때문에 Django는 각 어플리케이션 패키지 내에서 templates/ 서브 디렉토리를 자동으로 찾아서 대체하게 됩니다. (django.contrib.admin이 어플리케이션 임을 잊지 마십시오.)

  • 투표 어플리케이션은 복잡하지 않으며 사용자 정의 admin 템플릿이 필요하지 않습니다. 그러나 Django의 표준 admin 템플릿을 좀더 정교하게 필요에 맞게 수정 할 경우 프로젝트 템플릿 대신 어플리케이션의 템플릿을 수정하는 것이 더 현명합니다. 그렇게 하면 다른 새 프로젝트에 투표 애플리케이션을 포함시킬 수 있고, 필요할때는 커스텀 템플릿을 찾을수 있습니다. Django가 템플릿을 찾는 방법에 대한 자세한 정보는 템플릿 로딩 문서를 보십시오.

admin index 수정

  • 제목과 같이, Django admin 인덱스 페이지의 모양과 느낌을 수정하고 싶을 수도 있습니다.

  • 기본적으로 admin 어플리케이션과 함께 등록된 INSTALLED_APPS의 모든 어플리케이션을 사전순으로 표시합니다. 어쩌면 레이아웃을 크게 변경하고자 할 수 있습니다. 설사 그렇게 하더라도 인덱스는 admin의 가장 중요한 페이지이고, 사용하기 쉬워야 합니다.

  • 커스터마이징 할 템플릿은 admin/index.html입니다. (이전 섹션의 admin/base_site.html와 같은 작업을 합니다 - 기본 디렉토리에서 커스텀 템플릿 디렉토리로 복사하십시오). 파일을 편집하면 app_list라는 템플릿 변수를 사용하는 것을 볼 수 있습니다. 이 변수는 설치된 모든 장고 앱을 포함합니다. 이를 사용하는 대신 최선의 방법이라고 생각한다면 개체 별 admin 페이지에 대한 링크를 하드 코딩 할 수 있습니다.


admin 커스텀 참고 자료

profile
도메인 중심의 개발, 깊이의 가치를 이해하고 “문제 해결” 에 몰두하는 개발자가 되고싶습니다. 그러기 위해 항상 새로운 것에 도전하고 노력하는 개발자가 되고 싶습니다!

0개의 댓글