2012. 4. 27. 14:13

[06] django admin site

참고 : http://www.djangobook.com/en/2.0/chapter06/

web site의 특정 계층을 위한 admin interface(관리자 인터페이스)는 infrastructure의 필수 부분으로 자리잡았다. 이는 web 기반의 interface이고, 신뢰된 site 관리자로 제한하며, 그는 site content를 추가, 편집 그리고 삭제가 가능하다. 몇몇 일반적인 예로, blog에 글을 post 할때 쓰이는 interface, 적절한 사용자 생성의 댓글을 사용하는데 쓰이는 백엔드 site 관리자, 그리고 당신의 고객이 생성한 web site를 릴리즈 업데이트하는데 사용되는 도구등이 해당된다.

admin interface는 만드는데 지루하다는 문제가 있다. web 개발은 공개적인 기능을 개발할 때 즐거운데, admin interface는 늘 같은 내용이다. 사용자 인증, form을 표시하고 처리하기, 입력 검증, 기타 등등을 해야 한다. 이는 지겹고 반복적이다.

그래서 django에서는 이러한 지루하고 반복잡업에 대해 어떻게 접근할까? 단지 두세줄의 code 혹은 없이도 가능하게 한다. django로 admin interface를 만드는것은 해결된 문제이다.

본 장은 django의 자동 admin interface에 대해 다루기로 한다. model에 있는 metadata를 읽어 기능이 동작하게 되는데, 이는 site 관리자가 즉각 시작할 수 있는 강력하고 생산성이 준비된 interface를 제공하기 위함이다.  여기서 우리는 이 기능을 어떻게 활성화, 사용, 그리고 커스텀할지를 알려준다.

우리는 당신이 django의 admin site를 사용하지 않더라도 본 chapter를 읽기를 권장한다. 왜냐하면, admin-site 사용법과 상관없이 django의 모든것을 적용할 수 있는 몇몇 개념이 소개되기 때문이다.

django.contrib package

django의 자동 admin은 django.contrib이라 불리는 django 기능의 한 부분인데, 이는 code framework에 많은 유용한 add-on이 포함되어 있다. django.contrib을 python 표준 라이브러리와 동일하게 생각하면 된다. 당신의 application에서 다시 개발할 필요가 없도록 django에서 묶어놓은 것이다.

admin site는 django.contrib의 첫 부분인데, 이 책에서 다루고 있다. 기술적으로 django.contrib.admin으로 불려진다. django.contrib의 다른 가능한 기능은 사용자 인증 시스템(django.contrib.auth), 세션 지원(django.contrib.sessions), 그리고 사용자 코멘트(django.contrib.comments)등을 지원한다. 다양한 django.contrib 기능을 알고 있다는것은 당신을 django 전문가로 만들게 할 것이고, chapter 16에서 자세히 설명할 것이다. 지금은 django는 많은 훌륭한 add-on이 있고, 그들은 django.contrib에 있다는 것만 알고 있자.

admin interface 활성화 하기

django admin site는 옵션사항인데, 단지 몇개의 특정 종류의 site만 사용하기 때문이다. 이는 당신 project에 그것을 활성화하는데 단지 몇개의 과정만 필요하다는것을 의미한다.

처음으로, setting 파일에 다음 사항을 반영한다.

  1. INSTALLED_APPS에 'django.contrib.admin'를 추가한다. (추가할때, 그 순서는 중요하지 않으나, 알파벳 순서를 지키는것이 가독성에 좋다.)
  2. INSTALLED_APPS에 'django.contrib.auth', 'django.contrib.contenttypes', 그리고 'django.contrib.sessions'가 있는지 확인한다. django admin site는 이 3개의 package를 필요로한다.
    (이후에 설명될 "admin site에 model 추가하기"를 위해 'mysite.books'가 필요할 지 모른다)
  3. MIDDLEWARE_CLASSES에 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware'가 있는지 확인한다.

settings.py는 대략 아래와 같을 것이다.

...
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
...
INSTALLED_APPS = (
	'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
	
    #'django.contrib.sites',
    #'django.contrib.messages',
    #'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    #'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    # 아래 "admin site에 model 추가하기"에 의해 추가됨 
    #'mysite.books'
)
...

두번째로 python manage.py syncdb를 실행한다. 이 step은 admin interface가 사용할 database table을 추가적으로 설치한다. syncdb를 INSTALLED_APPS에 있는 'django.contrib.auth'로 실행하면 superuser 생성에 대해 질문을 받게 된다. 만약 이를 수행하지 않는다면, admin user 계정을 생성하기 위해 python manage.py createsuperuser를 실행해야 한다. 그렇지 안핟면, admin site에 로그인할 수 없다.

C:\mydjango\mysite>python manage.py syncdb
Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table django_content_type
Creating table django_session

You just installed Django's auth system, which means you don't have any superuse
rs defined.
Would you like to create one now? (yes/no): y
Please enter either "yes" or "no": yes
Username (leave blank to use 'administrator'): greenfish
E-mail address:
foo@bar.com
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

C:\mydjango\mysite


세번째로, URLconf(urls.py)에 admin site를 추가한다. 디폴트로 django-admin.py startproject는 django admin을 위해 주석 처리한 code가 있다, 그리고, 이를 주석 해제하면 된다. 다음과 같이 수정한다.

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
...
    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
...
)
위 설정의 일부로 django의 admin site를 볼 수 있다. python manage.py runserver를 실행한뒤, http://127.0.0.1:8000/admin/에 들어가 보면 된다.


admin site 이용하기

admin site는 기술자가 아닌 사람들에의해 사용될 것을 예상하여 설계되었다. 그럼에도 불구하고 기초적인 기능은 익히는것이 좋다.

처음 들어가보면, 아래와 같이 로그인화면을 볼 수 있다.



username과 password로 로그인하면 superuser를 추가한 것이다. 만약 로그인할 수 없다면, 이미 superuser를 생성을 확인해 봐야 한다. python manage.py createsuperuser를 실행해 보기 바란다.

일단 로그인하였다면, admin 홈페이지를 보게될 것이다. 이 page는 admin site에서 편집할 수 있는 모든 종류의data를 나열한다. 이때, 아직 model을 활성화하지 않았기 때문에, 목록은 비어있다. 단지 Groups and Users만 있는데, 이는 기본으로 포함된 편집가능한 model들이다.

django admin site에 있는 data의 각 type은 변경 내역(change list)편집창(edit form)을 가진다. change list는 database에 있는 모든 가능한 object를 보여주고, edit form은 database에 있는 특정 record에 대한 추가/변경/삭제를 가능하게 한다.

(Note : admin-site의 언어 선택은 추후 chapter 19에서 다룬다)

"Users"에 있는 "Change" 링크를 선택하면, user에 대한 변경사항을 보여준다.


이 page는 database의 모든 사용자를 나열한다. SELECT * FROM auth_user; SQL query문에 대한 web 버전이라고 생각하면 된다. 만약 이후에 진행될 예제를 통해 사용자 추가등을 실행했다면, 더만은 user를 보게될 것이고 필터링, 정렬 그리고 검색등을 수행할 수 있다.

당신이 추가했던 username(여기서는  greenfish)를 선택하면, 다음과 같은 edit form을 보게 된다.



이 page는 user의 속성(성, 이름, 기타 권한등등)을 변경하도록 해준다. 또다른 주요 사항으로는 다른 type의 field는 다른 위젯으로 나타난다는 것인데, 예를 들어, date/time field는 calendar control, boolean field는 checkbox, character field는 간단한 text input으로 구성되어 있다.

화면 하단의 delete button을 통해 record를 삭제할 수 있다. 이는 다시 확인창을 발생시키는데, 함께 삭제되는 의존성이 있는 object도 표기된다. 예를 들어, publisher를 삭제한다면, publisher를 가진 모든 book은 함께 사제될 것이다.

"Add" button을 통해 record를 추가할 수 있다. 이는 당신이 값을 채워 넣어야할 내용을 비워서 보여준다.


당신이 입력한 값에 대한 검증또한 수행해 준다. 필수 항목을 누락한채 저장하려면 다음과 같은 오류창이 발생한다.


만약 기존에 있는 object를 편집했다면, History link를 실행할 수 있다. admin interface를 통한 변경은 저장되며 History link를 통해 확인할 수 있다.
만약 user의 e-mail을 수정했으면,


와 같이 되고, 그에 따른 History는 다음과 같다.


admin site에 model 추가하기

아직 결정적인 부분을 소개하지 않았다. admin site에 우리가 만든 model을 추가할 수 있는데, 이러한 interface를 이용하여 손쉽게 object를 추가/변경/삭제할 수 있다. chater 5의 books 예제를를 적용해 보도록 하자.

books directory(mysite/books)에서 admin.py를 입력하고 다음 code를 기입한다.

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book)
이 code에 의해 django admin site는 각각의 model을 제공받는다.

일단, 이를 수행하였다면, web browser를 통해 확인 바라며, "Books" section에 들어가 보기 바란다.
(잘하면, runserver를 다시 시작해야 할 지 모른다.)

각각의 3개 model마다 admin inteface가 모두 지원되었다. 그것도 아주쉽게...

record 추가나 수정을 시도하여 database에 몇몇 data를 생산하기 바란다. 만약 이전의 chapter 5 예제를 실행하였다면, Publisher object에 이미 몇개의 data가 들어 있을 것이다.

가치있는 기능중 하나로, Book model에 대해 many-to-many relationship과 foreign key 처리이다. Book model은 다음과 같을 것이다.
class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField()
	
	def __unicode__(self):
		return self.title
"Add book" page에서, publisher(Foreign key)는 select box로 표현되고 authors field(ManyToManyField)는 다중 select box로 구성된다.

두개의 field 모두 녹색의 + 버튼이 있는데, 이는 연관 records를 추가하도록 도와준다.

admin site 동작 방식

어떻게 admin site가 동작할까? 그다지 복잡하지는 않다.

server 시작시 urls.py로 부터 URLconf를 로드하였다면, admin을 활성화를 위한 기능으로 추가된 admin.autodiscover()를 실행한다. 이 함수는 INSTALLED_APP를 조사하고 각각의 installed app에 있는 admin.py를 호출한다. 주어진 app에 admin.py가 있다면, 해당 file에 있는 code를 실행한다.

books app에 있는 admin.py에서 각각 admin.site.register()를 단순히 호출하는데, admin으로 주어진 model이 등록(register)된 경우에만 그러하다. admin site는 명시적으로 등록된 model에 대해 edit/change interface를 표시만 하게 된다.

django.contrib.auth는 고유의 admin.py를 포함하는데, 이는 admin에 있는 Users와 Groups를 자동으로 표기하기 위함이다. 다른 django.contrib.redirects와 같은 django.contrib app은 역시 admin을 추가하는데, web으로 부터 download한 많은 3rd party django application을 수행한다.

그 밖에, django admin site는 단지 django application이고, 그것은 자체 model, template, view 그리고 URLpattern을 가직고 있다. 당신의 URLconf로 추가할 수 있고, 당신 고유의 view에 연결할 수 있다. template, view, 그리고 URLpattern을 검사할 수 있는데, 이는 django codebase의 당신 복사본에 django/contrib/admin을 찾는것에 의해서 가능하다. 그러나 admin site 동작 방식을 custom할 수 있는 많은 방법이 있더라도 직접 수정하는 유혹에 빠지지는 말자. (django admin application을 뒤지기로 결정했다면, model에 대해 metadata를 읽음으로 꽤나 정제된 행위를 할 수 있음을 명시하고, 그래서 code를 읽고 이해하는데 들어가는 비용을 줄일 수 있을 것이다.)

field optional 만들기

잠시동안 admin site를 알아봤는데, 제약에 대해 주목해야 한다. edit forms은 모든 field가 채워져야 하는데, 대부분 optional field로 처리되길 바랄 것이다. 예를 들어, Author model의 email field를 optional하게 처리하는 것이다. 다시 말해, 비어있는 문자열을 허락하도록 하는 것이다. 현실 세계에서 모든 author가 email 주소를 가지는것이 아니기 때문이다.

email field가 optional임을 지정하기 위해 Book model(chapter 5에서 mysite/books/models.py에 있음)을 수정해야 한다. 다음과 같이 blank=True를 email field에 추가하면 된다.

class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField(blank=True)
이는 author의 email address가 빈값을 허락하라는 뜻이다. 기본값으로 blank=False인데, 빈값을 허락하지 않는다.

여기에서 재미있는 것이 있는데, __unicode()__ method를 제외하고 우리의 model은 database table의 정의대로 CREATE TABLE sql statement의 표현 형태로 서비스되었다. blank=True를 추가하여 database table의 형상을 간단히 정의한 것을 넘어 우리의 model을 확장하기 시작한 것이다. 이제 우리의 model class는 Author object가 무었인지 그리고 무었을 할 수 있는지에 대한 지식의 집합을 좀더 풍부하게 다루기 시작한 것이다. VARCHAR column으로 database에 email field를 표현되도록 한것 뿐만 아니라, django admin site에 optional field로 선언하였다.

blank=True로 선언하였다면, "Add author"(http://127.0.0.1:8000/admin/books/author/add/)를 다시 읽고 "Email" 글자가 bold체가 아님을 확인할 수 있다. 이는 요구하는 값이 아님을 나타나는 뜻으로 email 주소 없이 추가할 수 있다.


date와 numeric field optional 만들기

blank=True와 연관되어 date와 numeric field에도 적용되리라 생각할 수 있는데, 이는 배경 설명이 추가로 필요하다.

SQL은 빈값을 지정하는 고유의 방법으로, NULL을 사용한다. NULL은 "모름(unknown)"을 의미하거나 "무효한(invalid)" 혹은 기타 다른 정의로 사용되기도 한다.

SQL에서 NULL 값은 비어있는 문자열과 다른 의미인데, 이는 python object인 None이 비어있는 문자 ""와 다른것과 마찬가지 이다. 이는 특정 문자 field(예, VARCHAR)가 NULL 값과 비어있는 문자열 두개 모두 가능하다는 것이다.

이는 애매함과 혼란을 야기한다 : "왜 이 record는 NULL을 가지고 있고, 다른것은 비어있는 문자열이지? 그들간의 차이점이나 data 불일치(inconsistency)가 발생하지 않을까?"이다. 그리고 : "어떻게 비어있는 값을 가진 모든 record를 구할 것인지? 혹은 NULL record나 비어있는 문자열에 대해서도 혹은 비어있는 문자로 하나를 고르기만 한다면?"

이러한 애매함을 없애기 위해, django의 자동 생성된 CREATE TABLE statement(chapter 5에서 언급)는 NOT NULL을 각 column 정의부에 명시적으로 추가할 수 있다. 예를 들어, chapter 5로 부터의 Author model에을 위해 생성된 statement이다.
CREATE TABLE "books_author" (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(40) NOT NULL,
    "email" varchar(75) NOT NULL
)
;
대부분 이것의 기본 동작은 optional이며 data 불일치는 발생하지 않을 것이다. 그리고 admin site와 같은 django의 나머지 부분에도 잘 동작하는데, 만약 field를 비운채 저장하게 된다면, NULL 값이 아닌 빈 문자를 추가하게 된다.

그러나 date, time, 그리고 number와 같은 비어있는 문자열을 유효한 값으로 받아들일 수 없는 databas column type이 있다. 만약 date나 integer column에 비어있는 문자열로 추가하려고 한다면, 사용하는 database 종류에 따라(PostgreSQL은 엄격하게 예외를 발생함. MySQL은 받아줄 수도 없을 수도 있음), database 오류를 받게 된다. 이런 경우 NULL이 비어있는 값을 정의하는데 유일하게 사용된다. django model에서 null=True를 field에 추가하여 NULL을 허용할 수 있도록 한다.

다음을 언급하기 위해 많이 돌아왔다 : 만약 data field(예, DateField, TimeField, DateTimeField) 혹은 numeric field(예, IntegerField, DecimalField, FloatField)에 blank 값을 허용하려한다면, null=True blank=True를 모두 사용해야 한다.

예들 들어, Book model을 변경하여 publication_date에 blank를 가능하게 만들어보자.
class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField(blank=True, null=True)
null=True를 추가는것은 blank=True를 추가하는 것보다 더 복잡한데, null=True는 database의 의미(semantic)를 변경시키기 때문이고 그러므로, publication_date field로 부터 NOT NULL을 지우기 위해 CREATE TABLE statement를 변경한다.

이러한 몇몇 이유로 django는 database schema를 자동으로 변경하지 않는다. 그래서 model을 변경할 때 마다 적합한 ALTER TABLE statement를 실행해야 하는 책임이 있다. manage.py dbshell를 실행하여 database server의 shell에 들어가자. 다음이 NOT NULL을 제거하는 방법이다.
C:\mydjango\mysite>python manage.py dbshell
SQLite version 3.7.11 2012-03-20 11:35:50
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;
Error: near "ALTER": syntax error
sqlite>
(본 SQL 문법은 PostgreSQL에 해당되며, sqlite에서는 위와 같이 오류가 발생함)

이러한 shema 변경은 chapter 10에서 보다 자세히 다룰 것이다.

field label 수정(customizing) 하기

admin site의 edit form에서 각 field label은 field 이름으로 부터 생성된다. 그 알고리즘은 간단한데, django는 '_'를 ' '로, 앞 문자를 대문자로 변경한다. 예를 들어, publication_date는 "Publication date"로 변경된다.

그러나, field name은 field label로 사용하기 어려울 때도 있는데, 이런 경우에 label을 수정할 수 있다. verbose_name을 model field에 지정하여 가능해 진다.

예를 들어, Author.email field를 "e-mail"로 변경하고자 한다면 다음을 참고한다.

class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField(blank=True, verbose_name='e-mail')
변경하고 server를 다시 시작하면, edit form에 label이 변경된것을 확인할 수 있다.


verbose_name을 사용하면 첫 글자는 항상 대문자로 표시된다.

마지막으로 verbose_name을 위치가 있는 argument로 전달할 수 있는데, 이는 보다 간편한 문법이다. 아래는 그 예이다.

class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField('e-mail', blank=True)
이는 ManyToManyField나 ForeignKey field는 동작하지 않는데, 이는 첫 argument에 model class가 들어가기 때문이다. 이런 경우에는 verbose_name을 명시적으로 지정해야 한다.

ModelAdmin class 수정하기

여태껏 우리가 알아본 blank=True, null=True 그리고 verbose_name은 model-level 수정으로, 정확히 얘기하자면 admin-level 수정은 아니다. 이는 이러한 수정 사항들은 model의 한 부분이며 admin site에 의해 사용될 뿐이다. admin-specific은 아니다.

django admin은 admin site가 특정 model에 어떻게 동작하는지를 수정(customize)할 수 있는 option을 제공한다. 이러한 option은 ModelAdmin class에 있으며, 이는 특정 admin site instance에 있는 특정 model을 위한 설정을 포함하고 있는 class이다.

수정 목록(change list) 변경(custom)하기

Author model에 표시되는 수정 목록을 변경해 보도록 하자. 기본적으로 수정 목록은 각 object에 대해 __unicode__()의 결과를 표시한다. chapter 5에서 __unicode()__ method를 정의하였다.

class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField('e-mail', blank=True)
	
	def __unicode__(self):
		return u'%s %s' % (self.first_name, self.last_name)
결과적으로 Author object의 수정 목록은 각각의 성과 이름을 함께 표시한다.

변경 내역에 다른 field를 추가하여 기본 동작을 향상시킬 수 있다. 예를 들어, author의 e-mail 주소를 표기하고, 성과 이름을 정렬가능토록 한다.

이를 해결하기 위해 Author model에 ModelAdmin class를 정의한다. 이 class는 admin을 수정하는 키가 되는데 변경 내역 page를 표시하기 위한 field의 목록을 지정하도록 해주는 가장 기본적인 것중 하나이다. 다음과 같이 admin.py를 수정하면 된다.

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email')

admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book)
여기에서 우리가 한것을 정리하면 다음과 같다.
  • AuthorAdmin class를 정의하였다. 이 class는 django.contrib.admin.ModelAdmin을 상속받았고, admin model에 변경할 설정을 가지고 있다. "list_display"라는 단 하나의 수정을 지정하였는데 수정 목록에 표시할 field 이름을 정리한 것이다. 이 field 이름들은 model에 반드시 존재해야 한다.
  • admin.site.register() 호출을 Autor 다음에 AuthorAdmin을 추가하여 변경하였는데, 이는 다음과 같이 해석할 수 있다. : "AuthorAdmin option으로 Author model을 등록하라."

    admin.site.register() 함수는 ModelAdmin subclass를 두번째 argument로 option 처리하여 받아들인다. 만약 두번째 argument를 정의하지 않았다면, django는 해당 model에 대해 기본 admin option을 사용할 것이다.

이러한 변경된 사항을 가지고 해당 page를 다시 불러보자. 그리고 3개의 column으로 표시됨 확인할 수 있다. 덧붙여 column header를 클릭하면 정렬이 실행된다.


다음으로 간단한 검색 바(search bar)를 추가해 보자. search_fields를 AuthorAdmin에 추가한다.

class AuthorAdmin(admin.ModelAdmin):
	list_display = ('first_name', 'last_name', 'email')
	search_fields = ('first_name', 'last_name')
해당 page를 다시 읽으면 화면 상단에 검색 바가 뜨게 된다. 우리는 단지 admin 수정 목록에 first_name과 last_name field로 검색할 수 있는 검색 바를 포함하도록 알려줬을 뿐이다. 기대한 것처럼 대소문자 구별이 없으며, "bar"라고 검색하면 Barney 성과 Hobarson 이름을 찾게 된다.


다음으로, 수정 모록에 date filter를 추가해 보도록 하자.

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):
	list_display = ('first_name', 'last_name', 'email')
	search_fields = ('first_name', 'last_name')

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)

admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book, BookAdmin)
다른 종류의 option을 다루기때문에, BookAdmin이라는 구별된 ModelAdmin class를 생성하였다. 처음으로 list_display를 수정하였으며, 그다음 lists_filter를 사용하였는데, 이는 수정 목록 page의 오른족에 사용할 filter를 생성할수 있는 tuple을 지정하도록 한다. date field는 "오늘", "과거 7일", "이번달", 그리고 "올해"에 대한 filter를 제공한다. 다음과 같이 표시된다.


list_filter는 역시 DateField 이외의 다른 type의 field에서도 작동한다. 최소 2개 이상이 선택되었을때 표시된다,

date filter를 제공하는 다른 방법으로 date-hierarchy admin option을 사용하는 것이다.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
이것으로 수정 목록 page는 목록 상단에 navigation bar가 나타난다. 가능한 년도와 함께 시작되며, 달과 개별 일에 대해 더 상세히 들어갈 수 있다.


date_hierarchy는 tuple이 아닌 문자열을 받아들인다. 이는 하나의 date field만 받아들이기 위해서이다.

마지막으로 기본 정렬을 변경하는 것으로, 수정 목록 page가 표시될 때 항상 publication date에 의해 내림차순으로 정렬되도록 하는 것이다. 기본으로는 수정 목록은 class Meta(chapter 5) 범위 내의 model의 정렬을 따르게 되는데, ordering 값을 지정하지 않았다면, 정렬의 순서는 정의되지 않은 것이다.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
이 admin ordering option은 model들의 class Meta에 ordering을 따르도록 되어 있는데, list에 있는 첫 field name을 사용하도록 되어 있다. field 이름의 tuple 혹은 list를 전달하고, 내림차순 정렬인 경우 앞에 '-'를 붙여 주면 된다.

해당 page를 다시 읽으면 다음과 같다. "Publication date" header는 이제 작은 화살표 표시가 포함되고 관련 record들은 그에 따라 정렬되어 있다.


수정 목록을 변경하는 주요한 내용을 다뤘다. 이러한 option을 사용하면서 강력하고 생산적인 data 편집 interface를 단 몇줄로 만들 수 있다.

edit form 수정하기(customizing)

수정 목록을 수정한것 처럼 edit form도 많은 방법으로 변경이 가능하다.

처음으로 field의 순서를 수정해 보자. 기본으로 field의 순서는 model에서 정의한 순서를 따르도록 되어 있다. ModelAdmin 상속 class의 fields option을 이용하여 순서를 변경할 수 있다.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	fields = ('title', 'authors', 'publication_date', 'publisher')
이렇게 되면 edit form에서 field의 순서가 변경되게 된다.


다른 유용한 fields 옵션으로 전체가 편집되는 것으로 부터 특정 field를 제외할 수 있도록 한다. 단지 제외할 field(들)을 비워두면 된다. 만약 당신의 admin user들이 당신 data의 특정 부분을 편집하는데 신뢰된다던지 외부에 의해 field의 일부가 변경되는 경우 사용하면 된다. 예를 들어, book database에서 publication_date field를 편집하지 못하도록 할 수 있다.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	fields = ('title', 'authors', 'publisher')


결과적으로 books를 위한 edit form은 publication date를 지정할 방법을 제공하지 않는다. 이는 분명 유용한데, 다시 말해, 만약 publication date를 미루지 않는 author를 선호하는 편집자라면 그렇다.

user가 새로운 book을 추가할 때 이러한 불완전한 form을 사용한다면, django는 간단히 publication_date를 None으로 간주한다. 이는 즉 해당 field는 null=True가 되어 있어야 한다.

다른 것으로 many-to-many field에 대한 수정이 있다. book에 대한 edit form을 보았는데, admin site는 각각 ManyToManyField를 multiple-select box로 표현하는데, 이는 대부분의 논리적인 HTML 입력 widget이다. 그러나 multiple-select box는 사용하기가 불편하다. 만약 여러개의 item을 선택하려 한다면, CTRL 키를 누른채 선택해야 한다. admin site는 이것을 쉽게 설명하는 text를 추가할 수 있도록 해준다. 그러나 여전이 수백개를 포함하는 경우에는 다루기가 불편하다.

admin site의 결론은 filter_horizontal이다. BookAdmin을 추가하고 확인해보자.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	filter_horizontal = ('authors',)
(만약 여기까지 따라왔다면, 앞선 fields option을 제거했다)

다시 page를 읽어 들이면, "Authors" section을 보게 되고, 그것은 동적으로 option을 통해 검색을 가능케하고 "Available authors"로 부터 "Chosen authors" box로 혹은 그 역으로 특정 author를 이동할 수 있도록 하는 장식된 JavaScript filter를 사용한다.


10개 이상의 item을 가지는 ManyToManyField는 filter_horizental를 사용할 것을 권장한다. 이전의 간단한 multiple-select widget 보다 사용하기 편리하기 때문이다. 또한 filter_horizontal을 다중 filed에도 사용할 수 있다. 단지 tuple에 각 이름을 지정하면 된다.

ModelAdmin class는 역시 filter_vertical option도 지원한다. 이는 filter_horizontal과 동일하게 작동하나, JavaScript interface 결과를 수직대신 수평으로 쌓게 한다. 이는 단지 개인의 취향이다.


filter_horizontal과 filter_vertical은 ManyToManyField fields에만 동작하고, ForeignKey field는 동작하지 않는다. 기본으로 admin site는 간단한 <select> box를 ForeignKey field를 사용하나 ManyToManyField는 가끔 drop-down으로 표시되는 관계있는 object를 선택하는데 여러 부하가 발생하는 것이 발생되지 않길 원할 것이다. 예를 들어, 만약 book database에서 publisher가 수천개가 이를 정도로 커진다면, "Add book" form은 load하는데도 오래 걸릴 것이다. 왜냐하면 모든 publisher를 load해야 <select> box에 표시할 수 있기 때문이다.

이를 해결하기 위해 raw_id_fields를 사용하면 된다. ForeignKey field 이름으로 tuple 값을 세팅하고 이 fields는 간단한 text input box로 표시될 것이다.

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	filter_horizontal = ('authors',)
	raw_id_fields = ('publisher',)


input box에는 그럼 무었을 입력하는가? publisher에 해당되는 database id가 그 답이다. 보통 사람은 database id를 기억하지 못하므로, 옆의 돋보기 버튼을 통해서 선택할 수 있다.

Users, Groups, 그리고 Permissions

supseruser로 로그하였기 때문에, 당신은 임의의 object에 대해 생성, 편집, 그리고 삭제할 수 있다. 다른 환경은 다른 permission 시스템을 요구하기도 하는데, 모든이가 할 수 없도록 한다던지, superuser 이여야 한다던지가 해당된다. django의 admin site는 permission 시스템을 사용하는데, 그것은 그들이 필요한 interface의 단지 일부분만 특정 사용자가 접근 가능하게 해준다.

이러한 user 계정은 admin interface의 외부에서도 일반적으로 필요하다는 의미인데, 여기서는 admin user 계정에 한해서만 다루도록 한다. chapter 14에서 당신 site의 그 나머지에서 user 계정을 통합하는 것을 다루도록 한다. (admin site 뿐만 아니라)

당신은 다른 object와 유사한 admin interrface를 통해 user와 permission을 편집할 수 있다. 우리는 본 chapter 일찍이 Admin의 User와 Group section을 둘러보았다. User object는 표준 username, password, e-mail, 그리고 실명 field를 가지고 있으며 덧붙여 그 user에게 어떤 admin interface를 허락할지를 정의한 field도 있다. 우선, 다음과 같이 3개의 boolean flag를 가지고 있다.

  • "active" flag는 user의 활성화 여부를 조절한다. 만약 이 flag가 off라면 해당 user는 password가 맞더라도 log-in 할 수 없다.
  • "staff" flag는 admin interface레 log-in을 허락할지를 조절한다. public user와 administrator를 구별하는데 사용되는데, 자세한건 chapter 14에서 다룬다.
  • "superuser" flag는 추가할 admin interface에서 item을 생성하고 삭제하는 모든 access를 준다. 만약 해당 flag가 on이라면 모든 일반적인 permission은 무시된다.

"일반"적인 admin user, 다시 말해 active, non-superuser staff는 할당된 permission을 통해 admin 접근이 허가된다. admin interface를 통해 편집가능한 각 object는 3개의 permission을 가진다 : create permission, edit permission, 그리고 delete permission. permission을 user에게 할당하는 것은 이러한 permission에 의해 설명된 것들에 대한 접근을 허가한다.

만약 user를 생성할 때, 그 user에게 permission이 없고 이는 user 지정 permission을 부여하는 것에 달려있다. 예를 들어 publisher를 추가하고 변경하는 permission을 임의의 user에게 부여했으나 삭제할 permission을 주지 않았다면, 이러한 permission은 model 당 정의되어 있고, object 당 정의된 것이 아니다. "John은 어떤 책이라도 변경할 수 있다"이지 "John은 Apress에 의해 publish된 어떤 책을 변경할 수 있다"는 아니다. 뒷 부분 즉 object당 permission은 조금 복잡하고 이 책의 범위를 벗어난다. 그러나 django document에서 다루고 있다.

역시 user를 group에 할당할 수 있다. group은 해당 group의 모든 멤버에게 적용할 permission의 집합이라고 생각하면 된다. group은 user 일부에게 동일한 permission을 부여하는데 유용하다.

언제 그리고 왜 admin interface를 이용해야 하는가? 그리고 언제 사용하면 안되는가?

본 chapter를 통해 django의 admin site를 사용하는 좋은 아이디어가 있을지 모른다. 그러나 언제 그리고 사용하는지를 다루고, 그리고 언제 사용하면 안되는지도 확인해 보자.

django의 admin site는 특별히 빛나는데, 이는 비-기술자 user가 data에 접근할 때 이다. django가 처음 개발되었을 때 일상적인 온라인 기능의 개발은 다음과 같이 어디론가 가버렸다라고 신문에서 언급다.

  • project에 책임있는 reporter는 개발자중 한명을 만나고 가능한 data를 설명한다.
  • 개발자는 해당 data에 적합한 django model을 설계하고 reporter에게 admin site를 개설한다.
  • reporter는 누락되거나 관계없는 field를 찾기 위해 admin site를 검사하여 좀더 좋게 만든다. 개발자는 model을 반복하여 변경한다.
  • model에 동의되었다면, reporter는 admin site를 사용하여 data에 들어가보기 시작한다. 그와 동시에 프로그래머는 공개적으로 접근가능한 view와 template를 개발하는데 촛점을 맞출수 있다.

다른말로, django admin interface의 존재 이유는 컨텐츠 생산자와 프로그래머의 작업을 연속적으로 작업을 가능하게 한다.

그러나 admin site는 다른 몇가지 경우에 의해서도 유용하다.

  • data model 검사(inspect) : 몇몇 model을 정의하였다면, admin interface에서 호출하고 몇몇 dummy daat를 입력하는것등이 꽤나 유용할 때가 있다. 몇가지 경우에서 이는 data-modeling 실수 혹은 model에서 발생하는 다른 문제를 드러내 주기도 한다.
  • 습득(aquire)된 data 관리 : 외부 source(사용자 혹은 web crawler)로 부터 들어오는 data에 의존하는 application을 위해 admin site는 data의 검사 혹은 편집을 쉽게 하는 방법을 제공한다. database의 command-line utility 보다는 powerful 하지 않지만 훨씬 더 편리하다는 생각이 들 것이다.
  • 빠르고 더러운(quick and dirty) data 관리 app : admin site를 data 관리 app으로 스스로 만들어 사용할 수 있다. 다시 말해 비용을 추적한다는 뜻이다. 만약 공개하지 않고 당신 고유의 필요에의해 무엇인가 만든다면 admin site는 먼길을 제시한다. 이런 의미에서 당신은 그것을 보강된 것으로 생각할 수 있고 spreadsheet의 유사한 버전으로 간주된다.

명확한 한가지는 다음과 같다. : admin site는 가장 중요한 것은 아니다. 몇년 동안 의도적으로 서비스하지 않는 기능을 제공하기 위해 수정하고 자르는것을 봐왔다. 그것은 data에 대한 공개적인 interface로 의도되지 않았거나 data의 정제된 정렬과 검색을 허락하는 의도로 만들어졌다. 본 chapter 앞부분에서 알린바와 같이, 신뢰된 site 관리자를 위한 것이다. 이것을 잘 염두해둬야 admin site 사용을 효과적으로 사용할 수 있는 key가 된다.

'django > the django book study' 카테고리의 다른 글

[08] django Views와 URLconfs의 고급 기능  (0) 2012.05.30
[07] django의 form 처리  (0) 2012.05.06
[05] django의 model  (8) 2012.04.12
[04] django의 template  (14) 2012.04.05
[03] django 1.4의 view와 urlconfs  (5) 2012.04.04