backend/django

django tutorial: 어드민 사이트 변경- customizing admin (part7)

seul chan 2017. 3. 3. 22:23

장고의 자동 생성된 admin의 커스터마이징을 다뤄 볼 것이다.


Customize the admin form

admin.site.register(Question)으로 Question 모델을 등록함으로써 default form이 나타났다. 

=> admin의 look과 work를 커스터마이징하는 경우에는 원하는 옵션을 얘기해주면 됨


admin.site.register(Question) 라인을 재배치

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)

------

다음과 같은 패턴을 따르면 된다.

=> model admin class를 만들고, 

==> admin.site.register()의 두번째 argument로 그것(클래스를 취함)

위의 변화는 Publication date가 Question field 전에 오게 만들어준다.

(admin 사이트에서 확인)


만약에 많은 필드가 이쓴 경우에는, 필드셋으로 폼을 나눠주기를 원할 것이다

polls/admin.py에서

-----

from django.contrib import admin


from .models import Question



class QuestionAdmin(admin.ModelAdmin):

    fieldsets = [

        (None,               {'fields': ['question_text']}),

        ('Date information', {'fields': ['pub_date']}),

    ]


admin.site.register(Question, QuestionAdmin)

-----

필드셋 튜플을 활용하여 admin 사이트에서 Date information이라는 폼이 나타난 것을 볼 수 있다.



Adding related objects

각각의 Question들은 여러 개의 Choice를 갖고, admin page는 이들을 보여주지 않는다


2가지 해결방법이 있다

1. Choice를 Question에 등록했던 것처럼 admin 페이지에 등록하는 것

polls/admin.py에

-------

from django.contrib import admin


from .models import Choice, Question

# ...

admin.site.register(Choice)

-------

이렇게 추가해주면 Choice가 장고 어드민 페이지에서 볼 수 있다.


In that form, the “Question” field is a select box containing every question in the database. Django knows that a ForeignKey should be represented in the admin as a <select> box. In our case, only one question exists at this point.

Also note the “Add Another” link next to “Question.” Every object with a ForeignKey relationship to another gets this for free. When you click “Add Another”, you’ll get a popup window with the “Add question” form. If you add a question in that window and click “Save”, Django will save the question to the database and dynamically add it as the selected choice on the “Add choice” form you’re looking at.


하지만 이것은 Choice를 시스템에 추가하는 비효율적인 방법이다.



2. Question 오브젝트를 만들 때 Choice 들을 바로 추가해주는 방법이 더 낫다

choice 모델의 register()를 지우고, Question registration 코드를 수정한다.


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)

----------

이렇게 수정해준다. 


이는 장고에게 

"Choice object는 Question admin page에서 수정된다. defaul 값으로 3가지 choice 필드를 제공할 것이다"

라고 명령하는 것이다.


ChoiceInline을 TabularInline으로 바꿔주면 너무 많은 자리를 차지하는 문제도 해결된다.

polls/admin.py를

-----

class ChoiceInline(admin.TabularInline):

    ...

-----

이렇게 수정한다.



Customize the admin change list


이제 'change list' 페이지를 만들어보자


현재는 디폴트 값으로 각각의 오브젝트의 str()을 보여준다. 

=> 각각의 독립된 필드를 보여줄 필요성이 있음

이를 위해서 list_display admin 옵션을 사용한다

polls/admin.py를

----------

class QuestionAdmin(admin.ModelAdmin):

    # ...

    list_display = ('question_text', 'pub_date')

---------

를 추가해준다. 


was_published_recently() 메소드를 포함시켜보자

polls/admin.py를

---------

class QuestionAdmin(admin.ModelAdmin):

    # ...

    list_display = ('question_text', 'pub_date', 'was_published_recently')

---------

로 수정해주자

그럼 admin 페이지에서 text, date, 최근에 배포되었는지 세가지를 확인 가능하다.

각각의 헤더(was_published_recently를 제외하고)를 눌러서 정렬 가능하다


다음에 오는 몇몇 속성들을 통해서 메소드를 더 발전시키자

polls/models.py를 다음으로 수정시킨다.

-------

class Question(models.Model):

    # ...

    def was_published_recently(self):

        now = timezone.now()

        return now - datetime.timedelta(days=1) <= self.pub_date <= now

    was_published_recently.admin_order_field = 'pub_date'

    was_published_recently.boolean = True

    was_published_recently.short_description = 'Published recently?'

-------

그리고 polls/admin.py 파일의 QuestionAdmin에 list_filter를 추가해준다.

------

list_filter = ['pub_date']

------

이는 pub_date에 따른 필터를 추가시켜준다.


필터의 타입은 필드의 타입에 따라 다르게 표시된다. 

pub_date가 DateTimeField기 때문에 Any time, Today, Past 7 days... 등으로 필터가 표시된다.


이후에 searh_fields를 추가해준다.

-------------

search_fields = ['question_text']

-------------

이는 리스트 맨 위에 검색창을 만들어준다. 누군가 검색 용어를 입력하면, 장고는 question_text 필드를 찾는다. 


change lists give you free pagination.(??)

=> 디폴트는 페이지당 100 아이템. 

Change list pagination, (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_per_page)

search boxes, (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields)

filters, (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter)

date-hierarchies, (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.date_hierarchy)

column-header-ordering,(https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display)

참고하면 된다.

                        


Customize the admin look and feel


어드민 페이지 위에 'django adminstration'이 나오는 것은 이상하다. 

하지만 장고 템플릿 시스템을 이용해 쉽게 바꿀 수 있다. 


Customizing your project’s templates

프로젝트 디렉토리에 temlplates 디렉토리를 만든다.

템플릿은 장고가 접근할 수 있는 파일시스템 어디에나 존재할 수 있다. 

하지만 템플릿을 프로젝트 내에 넣는 것이 관리하기 편리하다.


mysite/settings.py 세팅 파일을 열고 DIRS 옵션에 TEMPLATES 세팅을 추가한다.

-----mysite/settings.py-----

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [os.path.join(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는 장고 템플릿을 불러올 때 체크하는 파일시스템 디렉토리의 리스트이다.


# Organizing templates

static file과 같이, 템플릿을 큰 템플릿 디렉토리에 같이 넣을 수 있다.

하지만, 각각의 애플리케이션에 속하는 템플릿들은 애플리케이션 내 템플릿 폴더에 넣는 것이 더 낫다.

이를 reusable apps tutorial(https://docs.djangoproject.com/en/1.10/intro/reusable-apps/)에서 다시 다룬다.


templates 폴더 안에 admin이라는 폴더를 만들고, 

admin/base_site.html 템플릿을 장고 자체 소스코드에서 복사한다.


# 장고 소스파일은 어디에 있을까?

장고 소스 파일이 어디에 있는지 찾기 힘들면, 다음 코드를 실행하면 된다.

$python -c "import django; print(django.__path__)"

나의 경우에는 

~/.pyenv/versions/djangostudy/lib/python3.6/site-packages/django/contrib/admin/temlpates/admin

안에 base_site.html이 있었다.

(터미널에서 복사 명령어는 

cp [옵션][원본파일명][목적 파일명/디렉토리명] 으로 한다.)


그리고 {{ site_header|default:_('Django administration') }}를 대체하면 된다.

자신이 원하는 사이트 명으로 넣어주면 된다. 

----------------

{% block branding %}

<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>

{% endblock %}

-----------------


이 방식은 어떻게 템플릿을 override하는지 보기 위해 사용했다.

실제 프로젝트에서는 django.contrib.admin.AdminSite.site_header 어트리뷰트를 통해 더 쉽게 커스터마이즈 가능하다


이 템플릿은 {% block branding %}이나 {{title}}과 같은 많은 텍스트가 포함된다.

{%이나 {{ 태그는 장고 템플릿 언어의 하나이다. 

이 언어들을 통해 장고는 최종 HTML 페이지를 만든다.

       

장고의 모든 default 어드민 템플릿은 재사용될 수 있다.

base_site.html에서 한 것 과 똑같이 하면 템플릿을 재사용 할 수 있다 

=> default 디렉토리에서 커스텀 디렉토리로 복사한 후, 변화를 적용시켜라

    

       

*Customizing your application’s templates


약삭빠른 사람들은 이렇게 물을 수 있다: DIRS가 디폴트값으로 비어 있는데, 장고가 어떻게 디폴트 어드민 템플릿을 찾을까요?

답은 이것이다: APP_DIRS이 TRUE로 세팅되어있으면 장고는 자동적으로 templates/ 서브디렉토리를 각각의 어플리케이션 패키지에서 찾는다.

(django.contrib.admin도 어플리케이션이니깐)


우리의 투표 앱은 복잡하지 않고, admin template을 커스텀 할필요는 없다.

하지만 더 고잡해지고 여러가지 기능이 추가되면 앱의 템플릿을 수정하는 것이 좋다.


이 방법으로 polls 애플리케이션을 다른 새로운 프로젝트에 포함시킬 수 있다..


template loading documentation(https://docs.djangoproject.com/en/1.10/topics/templates/#template-loading)을 보면 장고가 어떻게 템플릿을 찾는지 알 수 있다.


*Customize the admin index page

비슷한 방식으로, 장고의 admin index 페이지도 커스터마이즈 할 수 있다.

디폴트 값으로, INSTALLED_APP의 모든 앱들은 admin 애플리케이션에 알파벳순으로 등록이 되어있다


당신이 만약 이 레이아웃을 변경하고 싶다면, 인덱스는 admin의 가장 중요한 페이지이기 때문에 쉽게 변경할 수 있게 되어있다.


admin/index.html을 커스터마이즈 하면 된다.

(admin/base_site.html을 커스터마이즈 한 것처럼- 디폴트 폴더에서 복사해서 변경)

Edit the file, and you’ll see it uses a template variable called app_list. That variable contains every installed Django app. Instead of using that, you can hard-code links to object-specific admin pages in whatever way you think is best. (?? 무슨말인지 잘 모르겠다)


**What’s next?

비기너의 튜토리얼은 여기서 끝난다. 

where to go from here(https://docs.djangoproject.com/en/1.10/intro/whatsnext/)을 읽거나


파이썬 패키징에 익숙하고 polls 앱을 reusable app으로 쓰고싶다면

Advanced tutorial: How to write reusable apps(https://docs.djangoproject.com/en/1.10/intro/reusable-apps/)을 확인해라.