パーソナルツール
現在の場所: ホーム なごぶろ Djangoの管理画面のたぶん直前まで来た
このBlogについて
なごすいぶろぐ。「すべてはなごすいのために」。
カテゴリ
Plone (90)
Plone Products (22)
COREBlog2 (31)
COREBlog1 (29)
ReadingCOREBlog (7)
Zope (63)
Turbogears (18)
Django (12)
Python (23)
Linux (30)
Nagosui (11)
Design (30)
Misc (48)
moblog (5)
最近のエントリ
fastcgiでmercurial on nginx nyusuke 2008年10月08日
Kupuにスタイルを追加する nyusuke 2008年10月06日
Plone Help Centerを導入してみた nyusuke 2008年10月03日
ぽっどきゃすてぃんぐ落語が隔週から毎週に戻る nyusuke 2008年10月02日
最近のコメント
Re:WebデザイナーのためのDjangoはじめの一歩 nyusuke 2007年06月01日
Re:WebデザイナーのためのDjangoはじめの一歩 pateo 2007年05月31日
Re:東海Python Workshop 01終了 nyusuke 2007年05月31日
Re:東海Python Workshop 01終了 kfuruhata 2007年05月30日
 

Djangoの管理画面のたぶん直前まで来た

ブックマークアプリを作ってみるシリーズ。

前回まででモデルの定義はとりあえずOKとしますが、もう少し、特に管理画面を使いやすくするための設定を加えていくことにします。これを実現するために以下の3点をmodels.pyへ加えていきます。

  • def __str__():
  • class Admin:
  • class Meta:

__str__()

増田さんのドキュメントによれば:

__str__() は,オブジェクトに対して str() を呼び出した際に返す内容を定義するための Python の特殊メソッドです. Django はそこかしこで str(obj) を使っています.

そこらじゅうで使われてるらしいのでやっぱり設定しておくべきでしょう。インスタンスのタイトルなどを表示させるのがよさそうなので、ブックマークモデル、タグモデルの両方で以下のようにしておきました。

タグモデル:

class Tag(models.Model):
title = models.CharField(maxlength = 20)
(中略)

def __str__(self):
return self.title # titleアトリビュートで設定したものを返す

ブックマークモデル:

class Bookmark(models.Model):
title = models.CharField(maxlength = 30)
(中略)

def __str__(self):
return self.title # titleアトリビュートで設定したものを返す

もちろん他のものを返してもOKです。例えばブックマークではURLを返したいというような場合は:

class Bookmark(models.Model):
url = models.URLField(unique = True)
(中略)

def __str__(self):
return self.url # urlアトリビュートで設定したものを返す

とすればよいですが、長すぎるURLとかだと非常にうざくなりそうなので、タイトル・名前くらいがちょうどいいんじゃないでしょうか。

Meta

Metaクラスにはいくつかの設定項目がありますが、管理画面を使いやすくするのに便利な項目には例えば以下のようなものがあります。

verbose_name
オブジェクトの別名を設定する。例えばBookmarkに対して「'ブックマーク'」などとする。文字列で表現する
verbose_name_plural
オブジェクトの別名の複数形。verbose_nameと同じでもさほど問題なさげ。文字列で表現する
ordering
オブジェクトのリストをどのフィールドを元にして並べるのかを設定する 。文字列のリストで表現する

orderingにはフィールド名を指定します(指定しない場合はPrimary Key順、つまり追加した順に並びます)。フィールド名をそのまま記述すれば昇順に、マイナス「-」をつけると降順に並びます。例えば現在ブックマークモデルには以下のようなフィールドが定義されています:

class Bookmark(models.Model):
title = models.CharField(maxlength = 30)
url = models.URLField(unique = True)
summary = models.TextField(maxlength = 200, blank = True)
tags = models.ManyToManyField(Tag)
date = models.DateField(auto_now = True)

この場合は、title, url, summary, tags, dateで並び替えることができます。タイトル順にしたい場合は

class Meta:
ordering = ['title']

としてやります。dateで並ばせたい場合にはもちろん、

class Meta:
ordering = ['date']

dateで降順にしたい場合はマイナス(というかハイフン)を付けます。

class Meta:
ordering = ['-date']

*複数指定することもできますが、管理画面では最初のフィールドのみ有効になるようです。

ということで以下のような感じで設定しました。

タグモデルのMeta:

class Tag(models.Model):
title = models.CharField(maxlength = 20)
(中略)

class Meta:
ordering = ['title'] # titleで並べる
verbose_name = 'tags' # オブジェクトの別名
verbose_name_plural = 'tag items' # オブジェクトの別名の複数形

ブックマークモデルのMeta:

class Bookmark(models.Model):
title = models.CharField(maxlength = 30)
(中略)
date = models.DateField(auto_now = True)

class Meta:
ordering = ['-date'] # dateで降順に並べる
verbose_name = 'bookmarks' # オブジェクトの別名
verbose_name_plural = 'bookmark items' # オブジェクトの別名の複数形

Admin

Adminはモデルを管理画面に現すために必要です。とりあえずモデルの中にclass Admin:を書かなくてはなりません。で、モデルをどのように見せるのかをAdminクラスのアトリビュートとして表現していきます。設定項目はやはり増田さんのドキュメントを参照しましょう。

ここでは以下のようなアトリビュートを設定することにします。

list_display
管理画面に表示するフィールドを指定する。文字列のタプルとして表現する
date_hierarchy
日付で絞り込められるナビゲーションを追加するための項目。モデルの中にDateフィールドやDateTimeフィールドがある場合に使える
list_filter
項目を絞り込められるサイドナビゲーションを追加するための項目。何で絞り込むかを文字列のタプルとして表現する
search_fields
管理画面に検索ボックスを追加するための項目。検索対象となるフィールドを文字列のリストとして表現する

最初の「list_display」は管理画面でオブジェクトのリストを表示するときにどのフィールドを表示するのかを設定します。設定しないと__str__で設定したもののみ表示されてしまい、なんだか素っ気ない感じになってしまうので、例えばブックマークモデルのオブジェクトに関してはtitle以外にもurlとかtagとかを表示してやった方がいいかな、と。

その他の3つはオブジェクトを管理するにあたって絞り込みや検索など、使い勝手の良さを向上させるためのものですが、まぁ、無くてもよさげな雰囲気です。

ということでタグモデルのAdmin:

class Tag(models.Model):
title = models.CharField(maxlength = 20)
summary = models.CharField(maxlength = 100, blank = True)

class Admin:
# 管理画面でtitleとsummaryを表示
list_display = ('title', 'summary')

ブックマークモデルのAdmin:

class Bookmark(models.Model):
title = models.CharField(maxlength = 30)
url = models.URLField(unique = True)
summary = models.TextField(maxlength = 200, blank = True)
tags = models.ManyToManyField(Tag)
date = models.DateField(auto_now = True)

class Admin:
# 管理画面でtitleとurlとtagsを表示
# ホントは問題アリ(詳しくは後述)
list_display = ('title', 'url', 'tags')

# tagsとdateで絞り込みできるようにする
list_filter = ('tags', 'date')

# dateで絞り込みできるナビゲーションを追加
date_hierarchy = 'date'

# タイトルを対象として検索できるサーチボックスを追加
search_fields = ['title']

ただしこのままではブックマークモデルの「list_display」に少し問題があります。ドキュメントに特殊なケースとして書かれていますが、

list_display にはいくつか特殊なケースがあります:

  • ManyToManyField フィールドの表示は,テーブルの各行に対して個別に SQL 文を実行することになってしまうのでサポートしていません.どうしても表示させたいなら,カスタムメソッドをモデルに実装して,メソッドの名前を list_display に追加してください (list_display へのカスタムメソッドの追加については,後で詳しく説明しています).

ブックマークモデルでは「tags」は「ManyToManyField」なので以下のようではうまくいきません。

list_display = ('title', 'url', 'tags')

「'tags'」の代わりに、カスタムメソッドをモデルに実装してそのメソッド名をここに追加してやる必要があります。

カスタムメソッドを作る

あるブックマークに対して付与されているタグの一覧を得るメソッドを書いてやりましょう。データベースAPIの中にall()メソッドがありますので、これによってオブジェクトの一覧を取り出し、そのタイトルをリストとして表示してやるようなメソッドを書きます。

def selected_tags(self):
'''return selected tags'''
return [x.title for x in self.tags.all()]

リスト内包表記を使わずに表現するならこんな感じでしょうか?:

def selected_tags(self):
'''return selected tags'''
tag_titles = []
for tag_obj in self.tags.all():
tag_titles.append(tag_obj.title)
return tag_titles

いずれにしろこのselected_tagsというメソッドは、ブックマークに付与されたタグのタイトルをリストで返すようになります。ということで、

list_display = ('title', 'url', 'selected_tags')

これでいいでしょう。

まとめ

前回のモデルの定義に管理画面用のものを付け足して、以下のようになりました。

# vim: fileencoding = utf-8

from django.db import models



class Tag(models.Model):
title = models.CharField(maxlength = 20)
summary = models.CharField(maxlength = 100, blank = True)

def __str__(self):
return self.title

class Admin:
list_display = ('title', 'summary')

class Meta:
ordering = ['title']
verbose_name = 'tags'
verbose_name_plural = 'tag items'



class Bookmark(models.Model):
title = models.CharField(maxlength = 30)
url = models.URLField(unique = True)
summary = models.TextField(maxlength = 200, blank = True)
tags = models.ManyToManyField(Tag, filter_interface = models.HORIZONTAL)
date = models.DateField(auto_now = True)

def __str__(self):
return self.title


def selected_tags(self):
'''return selected tags'''
tag_titles = []
for tag_obj in self.tags.all():
tag_titles.append(tag_obj.title)
return tag_titles

class Admin:
list_display = ('title', 'url', 'selected_tags')
list_filter = ('tags', 'date')
date_hierarchy = 'date'
search_fields = ['title']

class Meta:
ordering = ['-date']
verbose_name = 'bookmarks'
verbose_name_plural = 'bookmark items'

*文中では触れませんでしたが、ブックマークのtagsアトリビュートに「filter_interface = models.HORIZONTAL」を追加しています。

ここでプロジェクトディレクトリにて「manage.py syncdb」すれば、これらのモデルがデータベーステーブルに反映されます。

カテゴリ
Django
トラックバック用URL:
http://nagosui.org/Nagosui/COREBlog2/ready-for-django-admin-3/tbping
コメントを追加

下のフォームに記入してコメントを追加できます。平文テキスト形式。

(必須)
(必須)
(必須)
(Required)
Enter the word