Django admin サイト

revision-up-to:11321 (1.1) unfinished

Django の最も強力な機能の一つに、自動生成される admin インタフェースがあり ます。 admin はモデルのメタデータを読み込んで、強力で実運用に耐えるインタ フェースを生成し、コンテンツの製作者がすぐにサイトにコンテンツを投入できる ようにします。このドキュメントでは、 Django の admin インタフェースを有効に したり、カスタマイズしたりする方法を解説します。

注意

admin サイトは Django 0.96 から大幅にリファクタされました。このドキュメ ントでは、よりカスタマイズ機能の充実した新しい admin サイトについて解説 しています。この admin サイトの仕様は、 Django の開発をよく追いかけてい る人なら、一度は “newforms-admin” という名前で耳にしたことがあるはずで す。

概要

Django admin サイトは、以下の 5 つのステップを通して有効化します:

  1. django.contrib.adminINSTALLED_APPS に追加します。
  2. admin インタフェースでの編集を可能にするモデルを決めます。
  3. 2 で決めたモデルに対して、必要なら ModelAdmin クラスを定義します。 ModelAdmin はモデルごとにカスタマイズした admin の機能やオプショ ンをカプセル化しています。
  4. AdminSite をインスタンス化して、モデルや ModelAdmin クラスを 指定します。
  5. AdminSite インスタンスを URLconf にフックします。

Other topics

See also

For information about serving the media files (images, JavaScript, and CSS) associated with the admin in production, see serving-media-files.

ModelAdmin オブジェクト

class ModelAdmin

ModelAdmin クラスは、 admin インタフェース上のモデルを表現しています。 このクラスは、アプリケーションの admin.py という名前のファイルに保存し ます。 ModelAdmin の簡単な例を以下に示します:

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

Do you need a ModelAdmin object at all?

In the preceding example, the ModelAdmin class doesn’t define any custom values (yet). As a result, the default admin interface will be provided. If you are happy with the default admin interface, you don’t need to define a ModelAdmin object at all – you can register the model class without providing a ModelAdmin description. The preceding example could be simplified to:

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)

ModelAdmin のオプション

ModelAdmin はとてもフレキシブルなクラスです。このクラスには、 admin イ ンタフェースをカスタマイズするためのオプションがいくつもあります。オプショ ンは、全て、 ModelAdmin のサブクラスで以下のように指定します:

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'
ModelAdmin.date_hierarchy

date_hierarchy をモデルの DateFieldDateTimeField に指定する と、変更リストのページに、指定フィールドの日付を使って日付ベースで絞り込み できるナビゲーションが組み込まれます。

例:

date_hierarchy = 'pub_date'
ModelAdmin.form

デフォルトの設定では、モデルに対して ModelForm が動的に生成され、追加/ 変更ページでフォームを生成するときに使われます。 form を独自の ModelForm と置き換えれば、追加/変更ページのふるまいを変更できます。

詳しくは、 admin にカスタムのバリデーションを追加する を参照してください。

ModelAdmin.fieldsets

admin の「追加 (add)」および「変更 (change)」ページのレイアウトを制御するに は、 fieldsets を使います。

fieldsets は 2 要素のタプルのリストです。各タプルは admin フォームペー ジ上の <fieldset> を表します (<fieldset> はいわばフォームの「セクショ ン」です)。

フィールドセットは (name, field_options) の形式をとります。 name はフィールドセットの名前を表す文字列で、 field_options はフィールドセッ ト内で表示したいフィールドの情報を入れた辞書です。この情報の中に、表示した いフィールドのリストも指定します。

django.contrib.flatpages.FlatPage モデルから抜き出した例を示します:

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('enable_comments', 'registration_required', 'template_name')
        }),
    )

このフィールドセットによって、 admin のページは以下のようになります:

../../../_images/flatfiles_admin.png

fieldsets を指定しない場合、 Django は AutoField でなく、かつ editable=True であるようなフィールドを、モデルに定義した順番に個別のフィー ルドセットとして表示します。

field_options 辞書には以下のようなキーを指定できます:

  • fields フィールドセット内に表示するフィールド名からなるタプルです。 必須のキーです。

    使い方:

    {
    'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
    }
    

    同じ行に複数のフィールドを表示したい場合、それらのフィールドをタプ ルでラップして入れます。下の例では、 first_namelast_name が同じ行に表示されます:

    {
    'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
    }
    
  • classes

    フィールドセットに適用される追加の CSS クラス名です。

    使い方:

    {
    'classes': ['wide', 'extrapretty'],
    }
    

    admin サイトのデフォルトのスタイルシートで定義されている便利なクラ スとして collapsewide があります。 collapse スタイ ルのフィールドセットは、 admin ページでは最初折り畳まれ (collapse) ており、小さな”クリックして展開 (click to expand)” リンクに置き換わっ ています。 wide スタイルのフィールドセットには水平方向に追加のス ペースが加わります。

  • description

    各フィールドセットの先頭の、ヘッダのすぐ下に表示する追加の文字列で、 オプションです。

    この文字列は admin 上で HTML エスケープ されません 。そのため、必 要ならそのまま HTML を入れられます。また、 HTML 固有の文字をエスケー プしたければ、 django.utils.html.escape() を使ってください。

ModelAdmin.fields

レイアウトを気にせず、単にモデルの一部のフィールドだけをフォームに表示した いだけの場合に、 fieldsets の代わりに使ってください。例えば、 django.contrib.flatpages.FlatPage モデルの admin フォームの簡単なバージョ ンを以下のように定義できます:

class FlatPageAdmin(admin.ModelAdmin):
    fields = ('url', 'title', 'content')

上の例では、 ‘url’, ‘title’, ‘content’ フィールドだけが順番にフォームに表示 されます。

Note

この fields オプションと fieldsets オプションの中の fields キーとを混同しないでくださいね。

ModelAdmin.exclude

この属性にフィールドの名前のリストを指定すると、指定したフィールドがフォー ムから除去されます。

例えば、以下のようなモデルがあったとします:

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3)
    birth_date = models.DateField(blank=True, null=True)

nametitle フィールドだけを含む Author モデルのフォームを 表示したければ、 fieldsexclude を使って、それぞれ以下のように 定義できます:

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title')

class AuthorAdmin(admin.ModelAdmin):
    exclude = ('birth_date',)

Author モデルは 3 つのフィールド name, title, birth_date しか持たないので、上の 2 つの例は全く同じフィールドを含むフォームを生成しま す。

ModelAdmin.filter_horizontal

ユーザビリティが紙一重の <select multiple> の代わりに、気の利いた控えめ な Javascript の「フィルタ」インタフェースを使います。フィルタインタフェー スを横並びにして表示させたいフィールドのリストを指定してください。フィルタ インタフェースを縦並びにしたい場合は filter_vertical を使ってください。

ModelAdmin.filter_vertical

filter_horizontal とほぼ同じですが、フィルタインタフェースを縦並びで表 示します。

ModelAdmin.list_display

admin の変更リストページに表示するフィールドを制御するには list_display を使います。

使い方:

list_display = ('first_name', 'last_name')

list_display を指定しなければ、 admin サイトは各オブジェクトの __unicode__() 表現を表示するカラムを一つだけ表示します。

list_display には 4 通りの設定方法があります:

  • モデルのフィールド名:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • モデルインスタンスを引数にとる呼び出し可能オブジェクト:

    def upper_case_name(obj):
        return "%s %s" % (obj.first_name, obj.last_name).upper()
    upper_case_name.short_description = 'Name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • ModelAdmin の属性名を表す文字列。呼び出し可能オブジェクトと同じよ うに動作します:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        def upper_case_name(self, obj):
          return "%s %s" % (obj.first_name, obj.last_name).upper()
        upper_case_name.short_description = 'Name'
    
  • モデルの属性名を表す文字列。ただし、 self はモデルインスタンスを 表します:

    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return self.birthday.strftime('%Y')[:3] + "0's"
        decade_born_in.short_description = 'Birth decade'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

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

  • フィールドが ForeignKey の場合、関連づけられているオブジェクトの __unicode__() を表示します。

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

  • フィールドが BooleanFieldNullBooleanField の場合、 TrueFalse の代りに “オン” や “オフ” を示すアイコンを表示 します。

  • モデルや ModelAdmin のメソッド、呼び出し可能オブジェクトの名前を 指定した場合、 Django はデフォルトでメソッドの出力を HTML エスケープ します。メソッドの出力をエスケープしたくない場合には、メソッドの allow_tags 属性の値を True にしてください。

    以下に例を示します:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_name(self):
            return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)
        colored_name.allow_tags = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name', 'colored_name')
    
  • TrueFalse を返すようなモデルの ModelAdmin のメソッド、 呼び出し可能オブジェクトの名前を指定した返す場合、メソッドの boolean 属性を True に設定しておくと、Django は「オン」や「オ フ」のアイコンを表示します。

    以下に例を示します:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return self.birthday.strftime('%Y')[:3] == '195'
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • __str__() および __unicode__() メソッドは他のモデルメソッドと 同じように list_display に入れられるので、以下のように書いても全 く問題ありません:

    list_display = ('__unicode__', 'some_other_field')
    
  • 通常、 list_display の要素のうち、実際のデータベースのフィールド に対応していないものは、変更リストページで並び順を変えるときのカラム には使えません。 Django はソートをすべてデータベースレベルで行うから です。

    ただし、 list_display のいずれかの要素が実際にデータベース上のあ るフィールドを指している場合、 admin_order_field という属性を使っ て、 Django にそのことを教えられます。

    例を示しましょう:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_first_name(self):
            return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
        colored_first_name.allow_tags = True
        colored_first_name.admin_order_field = 'first_name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    この例では、 Django は Admin 上で colored_first_name を並べ変える 際に first_name フィールドを使います。

list_display_links を設定すると、 list_display のどのフィールドを オブジェクトの「変更」ページにリンクするかを制御できます。

デフォルトでは、変更リストページはオブジェクトの変更ページ中の第一カラム、 すなわち list_display の先頭に指定したフィールドにリンクを張ります。 list_display_links を使うと、リンク先のカラムを変更できます。 list_display_links には、フィールド名のリストまたはタプルを (list_display と同じ形式で) 指定します。

list_display_links に指定するフィールド名は、一つでも複数でも構いません。 フィールド名が list_display に列挙されている限り、 Django はどんなに多 くの (あるいはどんなにわずかな) フィールドがリンクされていても問題にしませ ん。必要なのは、 list_display_links を使うには list_display を定義 しておかねばならない、ということだけです。

以下の例では、 first_name および last_name フィールドが変更リス トページにリンクされます:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'birthday')
    list_display_links = ('first_name', 'last_name')
ModelAdmin.list_editable

Set list_editable to a list of field names on the model which will allow editing on the change list page. That is, fields listed in list_editable will be displayed as form widgets on the change list page, allowing users to edit and save multiple rows at once.

Note

list_editable interacts with a couple of other options in particular ways; you should note the following rules:

  • Any field in list_editable must also be in list_display. You can’t edit a field that’s not displayed!
  • The same field can’t be listed in both list_editable and list_display_links – a field can’t be both a form and a link.

You’ll get a validation error if either of these rules are broken.

ModelAdmin.list_filter

admin の変更リストページの右側のサイドバーにあるフィルタを有効にするには、 list_filter を設定します。この値はフィールド名のリストにします。 各フィールド名は BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey のいずれかでなければ なりません。

以下の例は django.contrib.auth.models.User モデルからとったもので、 list_displaylist_filter の仕組みを示しています:

class UserAdmin(admin.ModelAdmin):
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    list_filter = ('is_staff', 'is_superuser')

上のコードによって、 admin の変更リストは以下のようになります:

../../../_images/users_changelist.png

(この例では、後述の search_fields も定義しています。)

ModelAdmin.list_per_page

admin 変更リストをページ分割 (paginate) で表示するときに、各ページに何個の アイテムを表示するかを決めます。デフォルト値は 100 です。

list_select_related を設定すると、 admin の変更リストページに表示するオ ブジェクトリストを取得する際に select_related() を使うよう Django に指 示できます。これにより、データベースクエリの発行数を抑えられます。

値は True または False にします。デフォルトは False です。

list_display のいずれかのフィールドが ForeignKey の場合、 Django は この設定に関わらず select_related() を使います。

select_related() の詳細は select_related() のドキュメント を参照してください。

ModelAdmin.inlines

後述の InlineModelAdmin を参照してください。

ModelAdmin.ordering

ordering を設定すると、 admin の変更リストにおける整列順を指定できます。 値はタプルからなるリストで、モデルの ordering パラメタと同じ形式で指定 します。

この値を指定しない場合、 Django はモデルのデフォルトの整列順を使います。

Note

Django はリストやタプルの最初の要素だけを考慮して、後の要素は無視します。

ModelAdmin.prepopulated_fields

フィールドの値を別のフィールドの値からセットさせたい場合は、以下のように、 prepopulated_fields にフィールド名を対応付けた辞書を設定してください:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

prepopulated_fields をセットすると、フィールドに小さな JavaScript のア クションが設定され、引数に指定したフィールドから値を自動的に取り込みます。 prepopulated_fields は、主に他の複数のフィールドから SlugField フィー ルドの値を生成するときに使います。値は、まず各ソースフィールドの値を結合し て、その結果が有効なスラグになるよう変換 (スペースをダッシュに置換するなど) して生成します。

DateTimeField, ForeignKey および ManyToManyFieldprepopulated_fields に指定できません。

ModelAdmin.radio_fields

デフォルトでは、Django の admin は ForeignKey のフィールドや choices の設定されたフィールドに対してセレクタボックス (<select>) イン タフェースを使います。 radio_fields にフィールド名を指定しておくと、 Django はセレクタボックスの代りにラジオボタンのインタフェースを使います。 例えば、 groupPerson モデル上の ForeignKey フィールド であれば、以下のように書けます:

class PersonAdmin(admin.ModelAdmin):
    radio_fields = {"group": admin.VERTICAL}

ラジオボタンの並び方を指定するシンボル、 HORIZONTAL または VERTICALdjango.contrib.admin モジュールにあります。

ForeignKeychoices パラメタのセットされたフィールド以外に radio_fields を使ってはなりません。

ModelAdmin.raw_id_fields

デフォルトでは、Django の admin サイトは ForeignKey フィールドに対して セレクタボックス (<select>) インタフェースを使います。しかし、時にはリレー ション先の全てのオブジェクトの入ったセレクタボックスが生成され、ドロップダ ウン表示されるのを避けたい場合もあります。

raw_id_fields には、ウィジェットを Input に変更したいフィールドのリ ストを指定します。 ForeignKey または ManyToManyField を指定できます:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ("newspaper",)
ModelAdmin.save_as

save_as を指定すると、 admin の編集フォームで「別名で保存 (save as)」機 能を使えるようになります。

通常、編集フォームには三つの保存オプション、すなわち「保存 (Save)」、「保存 して編集を続ける (Save and continue editing)」、「保存してもう一つ追加 (Save and add another)」があります。 save_asTrue にすると「保存 してもう一つ追加」は「別名で保存 (Save as)」に置き換わります。

「別名で保存」は、現在のオブジェクトをそのまま保存するのではなく、(新たな ID を持った) 別のオブジェクトとして保存することです。

デフォルトでは、 save_asFalse に設定されています。

ModelAdmin.save_on_top

save_on_top を指定すると、 admin の変更フォームの最上部に保存ボタンを追 加できます。

通常、保存ボタンはフォームの最下部だけに表示されます。 save_on_top を指 定すると、ボタンは最下部だけでなく最上部にも表示されます。

デフォルトでは、 save_on_topFalse です。

ModelAdmin.search_fields

search_fields を指定すると、 admin の変更リストページで検索ボックスを使 えるようになります。この値は、ユーザが検索クエリをテキストボックスに入力し たときに検索の対象に含めるフィールド名のリストです。

フィールドは CharFieldTextField のような何らかのテキストフィー ルドでなければなりません。 DB API の「リレーションを追跡する」表記を使えば、 ForeignKey を介したフィールドの指定も行えます:

search_fields = ['foreign_key__related_fieldname']

admin の検索ボックスで検索を実行すると、 Django は検索クエリを単語に分解し て、各単語を含むような全てのオブジェクトを返します。検索は大小文字を区別せ ず、 search_fields に指定したフィールドのうち少なくとも一つに単語が入っ ていればヒットします。例えば、 search_fields['first_name', 'last_name'] に設定されている場合、ユーザが john lennon を検索すると、 Django は以下のような WHERE 節を持った SQL と等価な検索を実行します:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

より高速な、あるいはより制約の厳しい検索を行うには、フィールド名の前に以下 のような演算子を置きます:

^

フィールドの先頭にマッチします。例えば、 search_fields['^first_name', '^last_name'] にして、ユーザが john lennon を検 索した場合、Django は以下のような WHERE 節の SQL に等価な検索を実行 します:

WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

このクエリを使うと、データベースはカラムの先頭部分だけをチェックすれば よく、カラム中のデータ全体を調べなくてもよくなるため、通常の '%john%' クエリよりも効率的に検索を実行できます。加えて、カラムにイ ンデクスが設定されていれば、データベースによっては LIKE クエリであっ てもインデクスを使ったクエリを実行できるという利点があります。

=

大小文字を区別しない厳密一致です。例えば、 search_fields['=first_name', '=last_name'] にして、ユーザが john lennon を検 索した場合、 Django は以下のような WHERE 節の SQL に等価な検索を実行 します:

WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

クエリ入力はスペース区切りなので、この例に従うと、 first_name'john winston' である (スペースを含む) ようなレコードは検索でき ないので注意してください。

@
全文検索マッチを実行します。デフォルトの search メソッドに似ていますが、 インデクスを使います。現在のところ MySQL でしか使えません。
ModelAdmin.formfield_overrides

This provides a quick-and-dirty way to override some of the Field options for use in the admin. formfield_overrides is a dictionary mapping a field class to a dict of arguments to pass to the field at construction time.

Since that’s a bit abstract, let’s look at a concrete example. The most common use of formfield_overrides is to add a custom widget for a certain type of field. So, imagine we’ve written a RichTextEditorWidget that we’d like to use for large text fields instead of the default <textarea>. Here’s how we’d do that:

from django.db import models
from django.contrib import admin

# Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

Note that the key in the dictionary is the actual field class, not a string. The value is another dictionary; these arguments will be passed to __init__(). See フォーム API for details.

Warning

If you want to use a custom widget with a relation field (i.e. ForeignKey or ManyToManyField), make sure you haven’t included that field’s name in raw_id_fields or radio_fields.

formfield_overrides won’t let you change the widget on relation fields that have raw_id_fields or radio_fields set. That’s because raw_id_fields and radio_fields imply custom widgets of their own.

ModelAdmin.actions

A list of actions to make available on the change list page. See Admin actions for details.

ModelAdmin.actions_on_top
ModelAdmin.actions_on_bottom

Controls where on the page the actions bar appears. By default, the admin changelist displays actions at the top of the page (actions_on_top = True; actions_on_bottom = False).

ModelAdmin.change_list_template

Path to a custom template that will be used by the model objects “change list” view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.change_form_template

Path to a custom template that will be used by both the model object creation and change views. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.object_history_template

Path to a custom template that will be used by the model object change history display view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.delete_confirmation_template

Path to a custom template that will be used by the view responsible of showing the confirmation page when the user decides to delete one or more model objects. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin のメソッド

ModelAdmin.save_model(self, request, obj, form, change)

save_model メソッドは HttpRequest, モデルインスタンス、 ModelForm インスタンス、オブジェクトの追加か変更かを表すブール値 (変更 の場合には True) を引数にとります。このメソッドを使えば、オブジェクトの 保存前 (pre-save) および保存後 (post-save) 処理を実行できます。

保存前に request.user をオブジェクトに保存するには、以下のようにします:

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
ModelAdmin.save_formset(self, request, form, formset, change)

save_formset メソッドは HttpRequest, モデルインスタンス、親クラスの ModelForm インスタンス、オブジェクトの追加か変更かを表すブール値 (変更 の場合には True) を引数にとります。

フォームセットの各モデルインスタンスの保存前に request.user をオブジェ クトに保存するには、以下のようにします:

class ArticleAdmin(admin.ModelAdmin):
    def save_formset(self, request, form, formset, change):
        instances = formset.save(commit=False)
        for instance in instances:
            instance.user = request.user
            instance.save()
        formset.save_m2m()
ModelAdmin.get_urls(self)

The get_urls method on a ModelAdmin returns the URLs to be used for that ModelAdmin in the same way as a URLconf. Therefore you can extend them as documented in URL ディスパッチャ:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = patterns('',
            (r'^my_view/$', self.my_view)
        )
        return my_urls + urls

Note

Notice that the custom patterns are included before the regular admin URLs: the admin URL patterns are very permissive and will match nearly anything, so you’ll usually want to prepend your custom URLs to the built-in ones.

However, the self.my_view function registered above suffers from two problems:

  • It will not perform and permission checks, so it will be accessible to the general public.
  • It will not provide any header details to prevent caching. This means if the page retrieves data from the database, and caching middleware is active, the page could show outdated information.

Since this is usually not what you want, Django provides a convenience wrapper to check permissions and mark the view as non-cacheable. This wrapper is AdminSite.admin_view() (i.e. self.admin_site.admin_view inside a ModelAdmin instance); use it like so:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = patterns('',
            (r'^my_view/$', self.admin_site.admin_view(self.my_view))
        )
        return my_urls + urls

Notice the wrapped view in the fifth line above:

(r'^my_view/$', self.admin_site.admin_view(self.my_view))

This wrapping will protect self.my_view from unauthorized access and will apply the django.views.decorators.cache.never_cache decorator to make sure it is not cached if the cache middleware is active.

If the page is cacheable, but you still want the permission check to be performed, you can pass a cacheable=True argument to AdminSite.admin_view():

(r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True))
ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)

The formfield_for_foreignkey method on a ModelAdmin allows you to override the default formfield for a foreign key field. For example, to return a subset of objects for this foreign key field based on the user:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
            return db_field.formfield(**kwargs)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

This uses the HttpRequest instance to filter the Car foreign key field to only the cars owned by the User instance.

Other methods

ModelAdmin.add_view(self, request, form_url='', extra_context=None)

Django view for the model instance addition page. See note below.

ModelAdmin.change_view(self, request, object_id, extra_context=None)

Django view for the model instance edition page. See note below.

ModelAdmin.changelist_view(self, request, extra_context=None)

Django view for the model instances change list/actions page. See note below.

ModelAdmin.delete_view(self, request, object_id, extra_context=None)

Django view for the model instance(s) deletion confirmation page. See note below.

ModelAdmin.history_view(self, request, object_id, extra_context=None)

Django view for the page that shows the modification history for a given model instance.

Unlike the hook-type ModelAdmin methods detailed in the previous section, these five methods are in reality designed to be invoked as Django views from the admin application URL dispatching handler to render the pages that deal with model instances CRUD operations. As a result, completely overriding these methods will significantly change the behavior of the admin application.

One comon reason for overriding these methods is to augment the context data that is provided to the template that renders the view. In the following example, the change view is overridden so that the rendered template is provided some extra mapping data that would not otherwise be available:

class MyModelAdmin(admin.ModelAdmin):

    # A template for a very customized change view:
    change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'

    def get_osm_info(self):
        # ...

    def change_view(self, request, object_id, extra_context=None):
        my_context = {
            'osm_data': self.get_osm_info(),
        }
        return super(MyModelAdmin, self).change_view(request, object_id,
            extra_context=my_context)

ModelAdmin のメディア定義

たまに、 CSS や JavaScript を追加・変更ビューに追加したい場合があります。 ModelAdmin に内部クラス Media を定義すれば、これを実現できます:

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        css = {
            "all": ("my_styles.css",)
        }
        js = ("my_code.js",)

これらのメディア名のパスには MEDIA_URL の内容が前置されます。また、 forms の通常のメディア定義 と同じ規則が当てはま ります。

admin にカスタムのバリデーションを追加する

admin にカスタムのバリデーションを追加するのはとても簡単です。 admin インタ フェースは django.forms を再利用しているので、 ModelAdmin クラス を使えばフォームを指定できます:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

MyArticleAdminForm は、 import できる場所ならどこにでも置けます。フォー ムの中で、任意のフィールドにカスタムのバリデーションコードを追加できます:

class MyArticleAdminForm(forms.ModelForm):
    class Meta:
        model = Article

    def clean_name(self):
        # do something that validates your data
        return self.cleaned_data["name"]

このとき、 ModelForm を使うことが重要です。他のクラスではうまくいきませ ん。詳しくは forms ドキュメント内の カスタムのバリデーション を参照してください。 モデルフォームのバリデーションに関する注意 にも、さらに詳しい情報があります。

InlineModelAdmin オブジェクト

admin インタフェースには、他のモデルクラスのインスタンスを同じページで編集 する機能があります。この機能をインライン編集と呼びます。例えば以下のような 二つのモデルがあったとします:

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author)
   title = models.CharField(max_length=100)

ある著者 (Author) オブジェクトのページで、著者の書いた本 (Book) オブジェク トの情報を編集したいなら、 ModelAdmin.inlines 属性に InlineModelAdmin を指定します:

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

Django は、 InlineModelAdmin のサブクラスとして、以下の二つを提供してい ます:

* ``TabularInline``
* ``StackedInline``

これら二つの違いは、単にレンダリングに使われるテンプレートに過ぎません。

InlineModelAdmin のオプション

InlineModelAdmin クラスは ModelAdmin のサブクラスなので、以下に挙げ る独自の機能の他に、 ModelAdmin の機能を全て継承しています:

model

インライン編集する対象のモデルです。必須の引数です。

fk_name

モデルの外部キーの名前です。たいていの場合、外部キーは自動的に決定できます が、親モデルに対して外部キーを複数張っているようなモデルの場合は、 fk_name を明示的に決める必要があります。

formset

デフォルト値は BaseInlineFormset です。独自のフォームセットを指定すれば、 色々とカスタマイズできます。インラインオブジェクトのフォームは モデルフォームセット で生成されています。

form

form の値は ModelAdmin から継承されます。この値は、インラインオブジェ クトのフォームセットを生成するときに fomrset_factory に渡されます。

extra

フォームセットが、初期のフォームに加えて表示する追加のフォーム数を制御しま す。詳しくは formsets のドキュメント を参照 してください。

max_num

インラインで表示するフォームの最大個数を制御します。この値は直接オブジェク トの数には関係しませんが、あまり小さな値が設定されていると、影響することも あります。詳しくは 編集可能なオブジェクトの数を制限する を参照してください。

raw_id_fields

デフォルトの設定では、 Django の admin は ForeignKey の選択に選択ボック スインタフェース (<select>) を使います。しかし、リレーション先の全てのイン スタンスをドロップダウンに表示するときのオーバヘッドを防ぎたいときがありま す。

raw_id_fields には、モデルの ForeignKeyManyToManyField をリ ストで指定します。 raw_id_fields に指定したフィールドは、 Input ウィ ジェットを使います:

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ("pages",)

template

インラインオブジェクトをレンダリングするときに使われるテンプレートです。

verbose_name

モデルの内部クラス Metaverbose_name の設定をオーバライドします。

verbose_name_plural

モデルの内部クラス Metaverbose_name_plural の設定をオーバライド します。

一つのモデルから複数の外部キーが張られている場合のインライン編集の扱い

一つのモデルに対して、複数の外部キーが張られている場合があります。以下のよ うなモデルを例に考えてみましょう:

class Friendship(models.Model):
    to_person = models.ForeignKey(Person, related_name="friends")
    from_person = models.ForeignKey(Person, related_name="from_friends")

Person の admin サイトで、インラインの追加・編集ページを表示したくても、 どの外部キーを辿らせるかは自動で決められません。従って、明示的に決めてやる 必要があります:

class FriendshipInline(admin.TabularInline):
    model = Friendship
    fk_name = "to_person"

class PersonAdmin(admin.ModelAdmin):
    inlines = [
        FriendshipInline,
    ]

中間モデルを介した多対多リレーションを扱う

デフォルトの設定では、 admin で多対多のリレーションを表す場合、 ManyToManyField を定義しているモデルの中でインライン表示されるウィジェッ トを使います。しかし、 ManyToManyFieldthrough 引数に中間モデル を指定した場合、 admin は ManyToManyField のウィジェットを表示しません。 これは、中間モデルの各インスタンスを表示するのに一つのウィジェットでは足り ないためと、複数ウィジェットを表示するために必要なレイアウトが中間モデルに よって変わってしまうためです。

しかし、それでもインラインで編集を行いたい場合があります。好運なことに、イ ンライン admin モデル (inline admin model) を使えば簡単に実現できます。 例として、以下のようなモデルを考えましょう:

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

中間モデルを admin で表示するには、まず Membership モデルに対するインラ インクラスを作成します:

class MembershipInline(admin.TabularInline):
    model = Membership
    extra = 1

上の簡単な例では、 InlineModelAdmin のデフォルトの設定を使って Membership モデルのインライン admin を定義しています。ただし、追加用の フォームの数を 1 つに制限しています。他にも、 InlineModelAdmin クラスの オプションを使えば、色々な設定をカスタマイズできます。

次に、 PersonGroup モデルの ModelAdmin クラスを定義します:

class PersonAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

class GroupAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

最後に、 PersonGroup を admin サイトに登録します:

admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)

これで、 admin サイトの PersonGroup の両方で、 Membership オブジェクトをインライン編集できます。

一般化リレーションをインラインで扱う

一般化リレーションオブジェクトもインラインで扱えます。以下のようなモデルが 定義されていたとしましょう:

class Image(models.Model):
    image = models.ImageField(upload_to="images")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey("content_type", "object_id")

class Product(models.Model):
    name = models.CharField(max_length=100)

Product の追加/変更ビューで Image インスタンスを編集したり追加した りしたいなら、 django.contrib.contenttypes.genericGenericInlineModelAdmin を使います。 admin.py で、以下のように設定 してください:

from django.contrib import admin
from django.contrib.contenttypes import generic

from myproject.myapp.models import Image, Product

class ImageInline(generic.GenericTabularInline):
    model = Image

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
    ]

admin.site.register(Product, ProductAdmin)

django.contrib.contenttypes.genericGenericTabularInlineGenericStackedInline を提供していて、その動作は通常のインライン編集と 同じです。詳しくは contenttypes のドキュメント を参照してください。

admin テンプレートのオーバライド

admin モジュールが admin サイトの様々なページを生成するときに使うテンプレー トは、その大半を比較的簡単にオーバライドできます。オーバライドは、特定のア プリケーションやモデルだけのためにもオーバライドできます。

プロジェクトの admin テンプレートディレクトリを設定する

admin テンプレートファイルは contrib/admin/templates/admin ディレクトリ に入っています。

テンプレートをオーバライドするには、まずプロジェクトの templates ディレ クトリ内に admin ディレクトリを作成します。プロジェクトのテンプレートディ レクトリとは、 TEMPLATE_DIRS の中に設定されているディレクトリのいずれか です。

次に、 admin ディレクトリ内に、アプリケーションの名前から取った名前のディ レクトリを作成します。アプリケーションのサブディレクトリの中に、さらにモデ ルからとった名前のサブディレクトリを作成します。このとき、 admin アプリケー ションはモデル名を小文字に変換した名前でディレクトリを探すことに注意しましょ う。ですから、大小文字を区別するファイルシステム上にアプリケーションを配置 しているのなら、ディレクトリ名が全て小文字で構成されているか確認してくださ い。

特定のアプリケーション向けに admin テンプレートをオーバライドしたければ、テ ンプレートを django/contrib/admin/templates/admin からアプリケーション 名のディレクトリ下にコピーして編集してください。

例えば、 my_app の全てのモデルの変更リストにツールメニューを追加したい なら、 contrib/admin/templates/admin/change_list.html をプロジェクトの templates/admin/my_app/ ディレクトリにコピーして必要な変更を施します。

Page という名前のモデルの変更リストだけにツールメニューを追加したいなら、 ファイルを templates/admin/my_app/page ディレクトリにコピーします。

admin のテンプレートはオーバライドすべきか、置き換えるべきか

admin テンプレートはモジュラー構造で設計されているので、必ずしもいつもテン プレート全体を置き換える必要はありませんし、そうしないよう勧めます。基本的 には、変更の必要のあるセクションだけをオーバライドするのがよいでしょう。

上に挙げた例の続きとして説明しましょう。 Page モデルの History ツー ルの隣に新しくリンクを追加したいとします。 change_from.html を眺めたあ と、オーバライドする必要があるのは object-tools ブロックだけだと分かっ たとしましょう。その場合、新たな change_form.html は以下のように書けま す:

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
  <ul class="object-tools">
    <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
    <li><a href="mylink/" class="historylink">My Link</a></li>
    {% if has_absolute_url %}
        <li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
            {% trans "View on site" %}</a>
        </li>
    {% endif%}
  </ul>
{% endif %}{% endif %}
{% endblock %}

これだけです!このファイルを templates/admin/my_app ディレクトリに置け ば、全てのモデル変更フォームでリンクが表示されるでしょう。

アプリケーションやモデル単位でオーバライドできるテンプレート

contrib/admin/templates/admin のテンプレートの全てが、アプリケーション やモデル単位でオーバライドできるわけではありません。以下のテンプレートはオー バライドできます:

  • app_index.html
  • change_form.html
  • change_list.html
  • delete_confirmation.html
  • object_history.html

この節で述べた方法でテンプレートをオーバライドできなくても、オーバライドし たい内容を templates/admin ディレクトリに配置することで、プロジェクト全 体の設定としてオーバライドできます。この方法は、カスタムの 404 ページや 500 ページをオーバライドするときに特に便利です。

Note

change_list_request.html のようなテンプレートは、カスタムの inclusion タグをレンダするために使われています。このテンプレートはオー バライドできますが、テンプレートを変更するときには、独自の inclusion タ グを作成しておいて、別の名前を付けておき、テンプレートで呼び出す方が よいでしょう。そうすれば、テンプレートを選択して使えるからです。

ルートテンプレートとログインテンプレート

インデクスページやログインページのテンプレートを変更したければ、 AdminSite インスタンスを自作して、 AdminSite.index_templateAdminSite.login_template プロパ ティの値を変更してください。

AdminSite オブジェクト

class AdminSite(name=None)

Django の管理サイトは django.contrib.admin.sites.AdminSite のインスタン スを使って表現しています。デフォルトでは、このクラスのインスタンスは django.contrib.admin.site としてすでに作成されていて、モデルや ModelAdmin インスタンスを登録できます。

独自のふるまいを実現する管理サイトを作りたければ、 AdminSite のサブクラ スを作成して、必要に応じてオーバライドや機能追加を行ってください。その後で、 作成したサブクラスを (他の Python クラスと同様に) 素直にインスタンス化して、 デフォルトの AdminSite インスタンスにモデルや ModelAdmin サブクラス を登録する代りに、作成したインスタンスに登録してください。

When constructing an instance of an AdminSite, you are able to provide a unique instance name using the name argument to the constructor. This instance name is used to identify the instance, especially when reversing admin URLs. If no instance name is provided, a default instance name of admin will be used.

AdminSite attributes

AdminSite.index_template

Path to a custom template that will be used by the admin site main index view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

AdminSite.login_template

Path to a custom template that will be used by the admin site login view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

URLconf に AdminSite インスタンスをフックする

Django admin サイト構築の最後のステップは、 AdminSite インスタンスの URLconf への設置です。設置を行うには、 URL を AdminSite.urls メソッドに 振り向けます。

以下の例では、デフォルトの AdminSite インスタンスである django.contrib.admin.site を、 /admin/ という URL にマップしていま す:

# urls.py
from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    ('^admin/', include(admin.site.urls)),

上の例では、 admin.autodiscover() を使って、 INSTALLED_APPSadmin.py モジュールを自動的にロードしています。

次の例では、 AdminSite インスタンス myproject.admin.admin_site/myadmin/ という URL にマップしています:

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import admin_site

urlpatterns = patterns('',
    ('^myadmin/', include(admin_site.urls)),
)

自作した AdminSite を使っているのなら、 myproject.admin モジュール の中で各アプリケーションの admin.py モジュールを import しているはずなので、 autodiscover を呼ぶ必要はありません。

一つの URLconf で複数の admin サイトを使う

Django で作られた一つの Web サイト上で、複数の admin サイトインスタンスを簡 単に運営できます。方法は、単に AdminSite インスタンスを複数にして別々の URL で設置するだけです。

The method for hooking AdminSite instances into urls has changed in Django 1.1.

下の例では、 /basic-admin//advanced-admin/ という二つの URL で、 myproject.admin.basic_sitemyproject.admin.advanced_site という AdminSite インスタンスを使って、別々のバージョンの admin サイトを運営し ています:

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import basic_site, advanced_site

urlpatterns = patterns('',
    ('^basic-admin/', include(basic_site.urls)),
    ('^advanced-admin/', include(advanced_site.urls)),
)

AdminSite instances take a single argument to their constructor, their name, which can be anything you like. This argument becomes the prefix to the URL names for the purposes of reversing them. This is only necessary if you are using more than one AdminSite.

Adding views to admin sites

Just like ModelAdmin, AdminSite provides a get_urls() method that can be overridden to define additional views for the site. To add a new view to your admin site, extend the base get_urls() method to include a pattern for your new view.

Note

Any view you render that uses the admin templates, or extends the base admin template, should provide the current_app argument to RequestContext or Context when rendering the template. It should be set to either self.name if your view is on an AdminSite or self.admin_site.name if your view is on a ModelAdmin.

Reversing Admin URLs

When an AdminSite is deployed, the views provided by that site are accessible using Django’s URL reversing system.

The AdminSite provides the following named URL patterns:

Page URL name Parameters
Index index  
Logout logout  
Password change password_change  
Password change done password_change_done  
i18n javascript jsi18n  
Application index page app_list app_label

Each ModelAdmin instance provides an additional set of named URLs:

Page URL name Parameters
Changelist {{ app_label }}_{{ model_name }}_changelist  
Add {{ app_label }}_{{ model_name }}_add  
History {{ app_label }}_{{ model_name }}_history object_id
Delete {{ app_label }}_{{ model_name }}_delete object_id
Change {{ app_label }}_{{ model_name }}_change object_id

These named URLs are registered with the application namespace admin, and with an instance namespace corresponding to the name of the Site instance.

So - if you wanted to get a reference to the Change view for a particular Choice object (from the polls application) in the default admin, you would call:

>>> from django.core import urlresolvers
>>> c = Choice.objects.get(...)
>>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,))

This will find the first registered instance of the admin application (whatever the instance name), and resolve to the view for changing poll.Choice instances in that instance.

If you want to find a URL in a specific admin instance, provide the name of that instance as a current_app hint to the reverse call. For example, if you specifically wanted the admin view from the admin instance named custom, you would need to call:

>>> change_url = urlresolvers.reverse('custom:polls_choice_change', args=(c.id,))

For more details, see the documentation on reversing namespaced URLs.