Django の admin サイト

Django のパワフルな特徴の1つは、自動的に生成される admin インタフェースです。あなたのモデルクラスからメタデータを読み取り、モデル中心のインタフェースを提供します。このインタフェースのおかげで、ユーザはあなたのサイトのコンテンツを操作できます。admin サイトのオススメの使い方は、組織内で利用する管理ツールに利用を制限することです。admin サイトは、あなたのサイトのフロントエンドやその周辺を含んだ全体を作成することを意図していません。

admin サイトは、カスタマイゼーションのためのたくさんのフックを持っています。しかしそれらのフックを使う際には気をつけてください。もしあなたが、データベースのテーブルとフィールドを使用しないような、よりプロセス中心のインタフェースを提供する必要があるなら、おそらく自分でビューを書いたほうが良いでしょう。

このドキュメントでは、Django の admin インタフェースを有効にして使用したりカスタマイズする方法について説明します。

概要

admin サイトは startproject で使用されるデフォルトのプロジェクトテンプレートで有効になります。

デフォルトのプロジェクトテンプレートを使用していない場合、要件は以下の通りです:

  1. 'django.contrib.admin' とその依存関係である django.contrib.auth, django.contrib.contenttypes, django.contrib.messages, および django.contrib.sessions を、 INSTALLED_APPS 設定に追加してください。
  2. DjangoTemplates バックエンドを、TEMPLATES 設定で構成し、django.template.context_processors.request, django.contrib.auth.context_processors.auth, および django.contrib.messages.context_processors.messagesOPTIONS'context_processors' オプションに含めてください。
  3. MIDDLEWARE 設定をカスタマイズしている場合、 django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddleware を含める必要があります。
  4. 管理サイトのURLをあなたのURLconfにフックする

これらのステップを踏んだ後、フックしたURL (デフォルトでは /admin/) を訪れることで、管理サイトを使用できるようになります。

ログイン用のユーザーを作成する必要がある場合は、createsuperuser コマンドを使用してください。デフォルトでは、管理サイトにログインするにはユーザーの is_staff 属性が True に設定されている必要があります。

最後に、アプリケーションのモデルのうちどれが管理インターフェースで編集可能であるべきかを決定します。それらのモデルごとに、ModelAdmin に記述されているように、管理サイトに登録します。

他のトピック

参考

本番環境での admin と関連する静的ファイル (画像、JavaScript、CSS) の配信について知りたい場合は、ファイルを配信する を参照してください。

問題が解決しない場合は、FAQ: 管理インタフェース を参照してみてください。

ModelAdmin のオブジェクト

class ModelAdmin

ModelAdmin クラスは、admin インターフェース内でモデルを表現する方法です。通常、アプリケーション内の admin.py に記述されます。ModelAdmin の例を見てみましょう:

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


class AuthorAdmin(admin.ModelAdmin):
    pass


admin.site.register(Author, AuthorAdmin)

いつでも ModelAdmin オブジェクトが必要なのか?

上記の例では、ModelAdminクラスはカスタム値を(まだ)定義していません。その結果、デフォルトの管理インターフェースが提供されます。デフォルトのadminインターフェースに満足している場合は、ModelAdminオブジェクトを定義する必要はまったくありません。ModelAdminの記述をせずにモデルクラスを登録できます。上記の例は、次のように簡略化できます。

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

admin.site.register(Author)

register デコレータ

register(*models, site=django.contrib.admin.sites.site)

ModelAdmin を登録するために、デレコータも用意されています:

from django.contrib import admin
from .models import Author


@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass

1 つ以上のモデルが与えられ、 ModelAdmin に登録されます。カスタムの AdminSite を使用している場合、site キーワード引数を使って渡してください:

from django.contrib import admin
from .models import Author, Editor, Reader
from myproject.admin_site import custom_admin_site


@admin.register(Author, Reader, Editor, site=custom_admin_site)
class PersonAdmin(admin.ModelAdmin):
    pass

このデコレータは、model admin クラスをその __init__() メソッド内で参照する必要がある場合(例: super(PersonAdmin, self).__init__(*args, **kwargs) )には使用できません。代わりに super().__init__(*args, **kwargs) のようにします。

admin ファイルを見つける

INSTALLED_APPS 設定内に 'django.contrib.admin' を記述すると、Django は自動的に各アプリケーション内で admin モジュールを探してインポートします。

class apps.AdminConfig

これは、admin に対するデフォルトの AppConfig クラスです。Django が開始すると autodiscover() を呼び出します。

class apps.SimpleAdminConfig

このクラスは AdminConfig と同じように動作しますが、autodiscover() を呼び出しません。

default_site

これはデフォルトの admin サイトのクラスやサイトインスタンスを返す呼び出し可能オブジェクトへのドット区切りのインポートパスです。デフォルトは 'django.contrib.admin.sites.AdminSite' です。使い方は デフォルトの admin サイトをオーバーライドする を参照してください。

autodiscover()

この関数は、インストールされた各アプリケーション内で admin モジュールをインポートするよう試みます。これらのモジュールは admin にモデルが登録されているものと想定されます。

通常、この機能を手動で呼び出す必要はありません。Django が開始するとき AdminConfig が呼び出してくれます。

カスタム AdminSite を使用している場合、通常はすべての ModelAdmin サブクラスをコードにインポートし、それらをカスタム AdminSite に登録します。その場合、自動検出を無効にするには、INSTALLED_APPS 設定で 'django.contrib.admin' の代わりに 'django.contrib.admin.apps.SimpleAdminConfig' を指定する必要があります。

ModelAdmin のオプション

ModelAdmin は非常に柔軟にできています。インターフェイスをカスタマイズするために、様々なオプションが用意されています。すべてのプションは ModelAdmin サブクラスで定義します:

from django.contrib import admin


class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = "pub_date"
ModelAdmin.actions

チェンジリストページで有効化するアクションのリストです。詳細は 管理アクション を参照してください。

ModelAdmin.actions_on_top
ModelAdmin.actions_on_bottom

ページ上のどこにアクションバーが表示されかをコントロールします。デフォルトでは、admin チェンジリストはページのトップにアクションを表示します (actions_on_top = True; actions_on_bottom = False)。

ModelAdmin.actions_selection_counter

アクションのドロップダウンの隣に選択用カウンターを表示するかどうかをコントロールします。デフォルトでは、admin チェンジリストは表示するようになっています (actions_selection_counter = True)。

ModelAdmin.date_hierarchy

date_hierarchy をモデル内の DateFieldDateTimeField の名前にセットすると、チェンジリストのページがそのフィールドによる日付ベースのドリルダウンナビゲーションを含むようになります。

実装例:

date_hierarchy = "pub_date"

__ ルックアップを使用して、関連するモデルのフィールドを指定することもできます。たとえば:

date_hierarchy = "author__pub_date"

この機能は、有効なデータに基づいて、適切に変化させます。たとえば、すべての日付が 1 月に収まっている場合、日のドリルダウンのみを表示します。

注釈

date_hierarchy は内部的に QuerySet.datetimes() を使用します。タイムゾーンサポートが有効 (USE_TZ = True) な際に注意すべき点について、ドキュメントを参照してください。

ModelAdmin.empty_value_display

この属性は、空(None、空の文字列、等)のレコードのフィールドに対するデフォルトの表示値をオーバーライドします。デフォルト値は - (ダッシュ)です。たとえば:

from django.contrib import admin


class AuthorAdmin(admin.ModelAdmin):
    empty_value_display = "-empty-"

AdminSite.empty_value_display ですべての admin ページもしくは特定のフィールドに対して empty_value_display をオーバーライドすることもできます:

from django.contrib import admin


class AuthorAdmin(admin.ModelAdmin):
    list_display = ["name", "title", "view_birth_date"]

    @admin.display(empty_value="???")
    def view_birth_date(self, obj):
        return obj.birth_date
ModelAdmin.exclude

この属性を使用する場合、フォームから除外するフィールドの名称をリストで指定します。

たとえば、以下のモデルを考えてみましょう:

from django.db import models


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

Author モデルに対するフォームが nametitle の 2 つのフィールドのみを含むようにしたい場合、以下のように fieldsexclude を指定することになります:

from django.contrib import admin


class AuthorAdmin(admin.ModelAdmin):
    fields = ["name", "title"]


class AuthorAdmin(admin.ModelAdmin):
    exclude = ["birth_date"]

Author モデルが 3 つのフィールド (nametitlebirth_date) しか持っていないので、上記の宣言によって生成されるフォームはまったく同じフィールドを持つことになります。

ModelAdmin.fields

"add" と "change" 上のフォームでシンプルなレイアウト変更 (有効なフィールドのみ表示、順序の変更、行のグルーピングなど) を行うには、fields オプションを使用してください。たとえば、以下のように、django.contrib.flatpages.models.FlatPage モデルに対して admin フォームのよりシンプルなバージョンを定義できます。

class FlatPageAdmin(admin.ModelAdmin):
    fields = ["url", "title", "content"]

上記の例では、指定したフィールド (urltitlecontent) だけが (結果として) フォーム上で表示されます。fieldsModelAdmin.readonly_fields で定義される値を持つことができ、読み取り専用で表示されます。

より複雑なレイアウトを作るには、fieldsets オプションを参照してください。

fields オプションは、 list_display と同じタイプの値を受け付けますが、呼び出し可能オブジェクトを受け付けないところが異なります。 readonly_fields にリスト化されている場合、モデルの名前とモデルの admin メソッドのみが使用されます。

1 つの行に複数のフィールドを表示するには、タプルで囲んでください。この例では、urltitle フィールドが同じ行に表示され、content フィールドは次の行に表示されます:

class FlatPageAdmin(admin.ModelAdmin):
    fields = [("url", "title"), "content"]

ModelAdmin.fieldsets オプションとの混同の可能性

この fields オプションと、次のセクションで説明する fieldsets における fields ディクショナリキーは別物です。

fieldsfieldsets オプションのどちらも存在しない場合、Django はデフォルトで AutoFieldeditable=True 以外の各フィールドを、単一のフィールドセットで、モデル内でフィールドが定義されたとおりの順番で表示します。

ModelAdmin.fieldsets

admin の "add" と "change" ページのレイアウトをコントロールするには、fieldsets をセットしてください。

fieldsets は、2 値タプルのリストで、各 2 値タプルは admin フォームページの <fieldset> を表します。 (<fieldset> はフォームの "section" です。)

2 値タプルのフォーマットは (name, field_options) で、name はフィールドセットのタイトル文字列を表し、field_options フィールドセットに関する情報のディクショナリで、表示するフィールドのリストを含みます。

django.contrib.flatpages.models.FlatPage モデルを用いた例は以下のようになります。

from django.contrib import admin


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

これにより、admin ページは以下のような見た目となります:

../../../_images/fieldsets.png

fieldsetsfields オプションのどちらも存在しない場合、Django はデフォルトで AutoFieldeditable=True 以外の各フィールドを、単一のフィールドセットで、モデル内でフィールドが定義されたとおりの順番で表示します。

field_options ディクショナリは以下のキーを持つことができます:

  • fields

    フィールドセット内に表示するフィールド名のリストまたはタプルです。このキーは必須です。

    実装例:

    {
        "fields": ["first_name", "last_name", "address", "city", "state"],
    }
    

    fields オプションと同様に、複数のフィールドを 1 行に表示するにはタプルでこれらのフィールドを囲んでください。この例では、first_namelast_name フィールドが 1 つの行に表示されます。

    {
        "fields": [("first_name", "last_name"), "address", "city", "state"],
    }
    

    fieldsModelAdmin.readonly_fields で定義される値を持つことができ、読み取り専用で表示されます。

    fields に呼び出し可能オブジェクトの名前を追加した場合、fields オプションと同じルールが適用されます: 呼び出し可能オブジェクトは readonly_fields 内でリスト化される必要があります。

  • classes

    フィールドセットに適用する追加的な CSS を含むリストないしタプルです。

    実装例:

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

    collapsewide の 2 つの便利なクラスがデフォルトの admin サイトのスタイルシートで定義されています。 collapse スタイルのフィールドセットは初期状態では admin 内で折りたたまれており、"click to expand" リンクで置き換えられています。 wide スタイルのフィールドセットは水平方向の追加的な余白が与えられます。

  • description

    各フィールドセットの上部、フィールドセットの見出しの下に表示されるオプションの追加テキストの文字列です。この文字列は TabularInline のレイアウト上、レンダリングされません。

    この値は、管理インターフェイスに表示されるときにはHTMLエスケープされないことに注意してください。これにより、HTML を含めることができます。あるいは、プレーンテキストと django.utils.html.escape() を使って HTML の特殊文字をエスケープすることもできます。

ModelAdmin.filter_horizontal

デフォルトでは、ManyToManyField<select multiple> で admin サイトで表示されます。複数選択のボックスは、たくさんのアイテムを選択するには不向きです。ManyToManyField をこのリストに加えると、代わりにかっこよくて控えめな JavaScript の "filter" インターフェースを使用します。非選択および選択済みのオプションは 2 つのボックスに並べて表示されます。垂直方向のインターフェースを使用するには filter_vertical を参照してください。

ModelAdmin.filter_vertical

filter_horizontal と同じですが、フィルタインターフェイスを垂直方向に表示し、非選択のオプションは選択済みのオプションの上部に表示されます。

ModelAdmin.form

デフォルトではモデルに対して ModelForm が動的に生成されます。追加と変更の両方のページで使用されるフォームです。独自の ModelForm を定義すれば、追加と変更のページでフォームの挙動を簡単にオーバーライドできます。あるいは、まったく新しいモデルフォームを作る代わりに、ModelAdmin.get_form() メソッドを使ってデフォルトのフォームをカスタムすることもできます。

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

Meta.model 属性を省略する

ModelFormMeta.model 属性を定義した場合、Meta.fields 属性 (もしくは Meta.exclude 属性) も定義する必要があります。しかし、admin 自身がフィールドを定義する方法を持っているため、Meta.fields 属性は無視されます。

ModelForm を admin のみで使用する場合は、ModelAdmin が使用する正しいモデルを提供するため、Meta.model 属性を省略するのが手っ取り早い解決法です。あるいは、Meta クラス内で fields = [] をセットして ModelForm のバリデーションの条件を満たすこともできます。

ModelAdmin.exclude が優先されます

ModelFormModelAdmin の両方で exclude オプションが定義されている場合、ModelAdmin は優先順位に従います。

from django import forms
from django.contrib import admin
from myapp.models import Person


class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        exclude = ["name"]


class PersonAdmin(admin.ModelAdmin):
    exclude = ["age"]
    form = PersonForm

この例では、生成されるフォームで "age" フィールドは除外されますが "name" フィールドは含まれます。

ModelAdmin.formfield_overrides

admin 内で使用するための Field のうちある程度の部分をオーバーライドする簡単 (だけど汚い) 方法を提供します。formfield_overrides はディクショナリで、フィールドクラスの構成時にフィールドに渡す引数のディクショナリをマッピングします。

これでは抽象的すぎるので、具体的な例を見てみましょう。formfield_overrides のもっとも一般的な使い道は、特定のタイプのフィールドに対してカスタムしたウィジェットを追加することです。大きなテキストフィールドを使用するために、デフォルトの <textarea> の代わりに RichTextEditorWidget を使いたいとしましょう。この場合、以下のように記述します。

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

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


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

ディクショナリ内のキーは文字列 ではなく 実際のフィールドクラスである点に注意してください。値は別のディクショナリです; これらの引数はフォームフィールドの __init__() メソッドに渡されます。詳細は フォーム API を参照してください。

警告

リレーションフィールド (例えば ForeignKeyManyToManyField) でカスタムウィジェットを使用したいときは、, raw_id_fieldsradio_fieldsautocomplete_fields にそのフィールドの名前を含まないようにしてください。

formfield_overrides は、raw_id_fieldsradio_fieldsautocomplete_fields のどれかがセットされたリレーションフィールドのウィジェットは変更しません。これは、raw_id_fieldsradio_fieldsautocomplete_fields の 3 つがこれら自身のカスタムウィジェットを暗示するからです。

ModelAdmin.inlines

後述の InlineModelAdmin オブジェクトと ModelAdmin.get_formsets_with_inlines() を参照してください。

ModelAdmin.list_display

admin のチェンジリストページでどのフィールドを表示するかコントロールするために、list_display をセットします。

実装例:

list_display = ["first_name", "last_name"]

list_display をセットしない場合、admin サイトは各オブジェクトの __str__() 表現を表示する単一の列を表示します。

list_display で使用できる値は 4 種類あります。最も単純なもの以外は、フィールドの表示方法をカスタマイズするために display() デコレータを使用できます。

  • モデルフィールドの名前。次に例を示します。

    class PersonAdmin(admin.ModelAdmin):
        list_display = ["first_name", "last_name"]
    
  • 1 つの引数 (モデルのインスタンス) を受け入れる呼び出し可能オブジェクトです。次に例を示します。

    @admin.display(description="Name")
    def upper_case_name(obj):
        return f"{obj.first_name} {obj.last_name}".upper()
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = [upper_case_name]
    
  • 1 つの引数 (モデルのインスタンス) を受け入れる ModelAdmin メソッドを表す文字列です。次に例を示します。

    class PersonAdmin(admin.ModelAdmin):
        list_display = ["upper_case_name"]
    
        @admin.display(description="Name")
        def upper_case_name(self, obj):
            return f"{obj.first_name} {obj.last_name}".upper()
    
  • モデルの属性や (必須の引数を持たない) メソッドを表す文字列です。次に例を示します。

    from django.contrib import admin
    from django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        @admin.display(description="Birth decade")
        def decade_born_in(self):
            decade = self.birthday.year // 10 * 10
            return f"{decade}’s"
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ["name", "decade_born_in"]
    

list_display に関する特殊な状況の注意点があります。

  • フィールドが ForeignKey の場合、 Django はリレーション先オブジェクトの __str__() を表示します。

  • ManyToManyField フィールドは、テーブル内で各行に対して個別の SQL ステートメントを実行する可能性があるため、サポートされていません。それでも使いたい場合は、モデルにカスタムメソッドを作成し、そのメソッドの名前を list_display に追加してください。 (list_display 内でのカスタムメソッドについてより詳しくは下記を参照してください。)

  • フィールドが BooleanField の場合、Django は True, False, None の代わりに、かわいい "yes", "no", "unknown" アイコンを表示します。

  • 与えられた文字列がモデル、ModelAdmin、呼び出し可能オブジェクトのどれかの場合、Django はデフォルトで HTML エスケープして出力します。ユーザーの入力をエスケープしたり非エスケープのタグを使う場合、format_html() を使用してください。

    以下は、モデルの例です。

    from django.contrib import admin
    from django.db import models
    from django.utils.html import format_html
    
    
    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)
    
        @admin.display
        def colored_name(self):
            return format_html(
                '<span style="color: #{};">{} {}</span>',
                self.color_code,
                self.first_name,
                self.last_name,
            )
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ["first_name", "last_name", "colored_name"]
    
  • これまでの例で見てきたように、呼び出し可能オブジェクト、モデルメソッド、または ModelAdmin メソッドを使用する場合、 display() デコレータで呼び出し可能オブジェクトをラップし、 description 引数を渡すことで、カラムのタイトルをカスタマイズできます。

  • フィールドの値が None、空の文字列、エレメントを持たない iterable のいずれかの場合、Django は - (ダッシュ) を表示します。この挙動は AdminSite.empty_value_display でオーバーライドできます。

    from django.contrib import admin
    
    admin.site.empty_value_display = "(None)"
    

    ModelAdmin.empty_value_display も使用できます。

    class PersonAdmin(admin.ModelAdmin):
        empty_value_display = "unknown"
    

    もしくは、フィールドレベルで以下のようにできます。

    class PersonAdmin(admin.ModelAdmin):
        list_display = ["name", "birth_date_view"]
    
        @admin.display(empty_value="unknown")
        def birth_date_view(self, obj):
            return obj.birth_date
    
  • 与えられた文字列がモデル ModelAdmin のメソッドか、 True, False, None を返す呼び出し可能オブジェクトの場合、 Django はそのメソッドを display() デコレータでラップし、 boolean 引数を True で渡すと、かわいい "yes", "no", "unknown" アイコンを表示します。

    from django.contrib import admin
    from django.db import models
    
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        @admin.display(boolean=True)
        def born_in_fifties(self):
            return 1950 <= self.birthday.year < 1960
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ["name", "born_in_fifties"]
    
  • __str__() メソッドは、他のモデルメソッドとまったく同様に list_display 内でも有効です。つまり、以下のような書き方は完璧に OK です。

    list_display = ["__str__", "some_other_field"]
    
  • 通常、実際のデータベースフィールドではない list_display の要素は、ソートに使用できません (Django のソートはすべてデータベースレベルで実行されるためです)。

    しかし、list_display の要素が特定のデータベースフィールドを表す場合、メソッドに display() デコレータを使用し、 ordering 引数を渡すことで、その事実を伝えることができます。

    from django.contrib import admin
    from django.db import models
    from django.utils.html import format_html
    
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        @admin.display(ordering="first_name")
        def colored_first_name(self):
            return format_html(
                '<span style="color: #{};">{}</span>',
                self.color_code,
                self.first_name,
            )
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ["first_name", "colored_first_name"]
    

    上記のコードは、admin 内で colored_first_name で ソートしようとするとき、first_name フィールドで並べ替えるよう Django に伝えます。

    引数 ordering で降順を示すには、フィールド名の前にハイフンをつけます。上記の例を使うと、次のようになります。

    @admin.display(ordering="-first_name")
    def colored_first_name(self): ...
    

    引数 Lordering はリレーション先モデルの値でソートするクエリのルックアップをサポートします。この例では、"author first name" カラムをリストに表示し、first name でソートできるようにしています。

    class Blog(models.Model):
        title = models.CharField(max_length=255)
        author = models.ForeignKey(Person, on_delete=models.CASCADE)
    
    
    class BlogAdmin(admin.ModelAdmin):
        list_display = ["title", "author", "author_first_name"]
    
        @admin.display(ordering="author__first_name")
        def author_first_name(self, obj):
            return obj.author.first_name
    

    クエリ式ordering 引数と一緒に使うことができます。

    from django.db.models import Value
    from django.db.models.functions import Concat
    
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        @admin.display(ordering=Concat("first_name", Value(" "), "last_name"))
        def full_name(self):
            return self.first_name + " " + self.last_name
    
  • list_display の要素はプロパティにすることもできます。

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        @property
        @admin.display(
            ordering="last_name",
            description="Full name of the person",
            boolean=False,
        )
        def full_name(self):
            return self.first_name + " " + self.last_name
    
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ["full_name"]
    

    ただし、@property@display より上でなければなりません。display() デコレータを使用するのではなく、直接表示関連の属性を設定する古い方法を使用している場合は、@property デコレータではなく、property() 関数を使用しなければならないことに注意してください。

    def my_property(self):
        return self.first_name + " " + self.last_name
    
    
    my_property.short_description = "Full name of the person"
    my_property.admin_order_field = "last_name"
    my_property.boolean = False
    
    full_name = property(my_property)
    
    Changed in Django 5.0:

    プロパティの boolean 属性をサポートしました。

  • list_display のフィールド名はHTMLの出力でも <th> 要素に column-<field_name> という形でCSSクラスとして表示されます。これは例えばCSSファイルでカラムの幅を設定するのに使うことができます。

  • Django は、list_display の各要素を以下の順番で解釈しようとします。

    • モデルのフィールド。
    • 呼び出し可能オブジェクト。
    • ModelAdmin 属性を表す文字列。
    • モデル属性を表す文字列。

    たとえば、first_name がモデルフィールドと ModelAdmin 属性の両方で存在する場合、モデルフィールドの方が使用されます。

list_display 内のフィールドにおいて "変更" ページへのリンクをコントロールするには、list_display_links を使用してください。

デフォルトでは、チェンジリストページは最初のカラム (list_display で最初に指定したフィールド) に各アイテムの変更ページへのリンクが貼られています。しかし、list_display_links を使って変更できます。

  • リンクを貼らない場合は None をセットしてください。

  • (list_display と同様のフォーマットで) リンクに変換したいカラムのフィールドのリストないしタプルをセットしてください。

    1 つないし複数のフィールドを指定できます。list_display にある限り、Django はいくつのフィールドがリンクになろうと気にしません。唯一の要件は、list_display_links をこの方式で使いたいときは list_display を指定することです。

以下の例では、first_namelast_name フィールドがチェンジリストページでリンクされます。

class PersonAdmin(admin.ModelAdmin):
    list_display = ["first_name", "last_name", "birthday"]
    list_display_links = ["first_name", "last_name"]

以下の例では、チェンジリストページのグリッドにはリンクがなくなります。

class AuditEntryAdmin(admin.ModelAdmin):
    list_display = ["timestamp", "message"]
    list_display_links = None
ModelAdmin.list_editable

チェンジリストページ上での編集を有効にしたいモデルのフィールド名のリストを list_editable にセットしてください。list_editable に指定されたフィールドは、チェンジリストページ上でフォームウィジェットとして表示され、ユーザーは複数の行を一度に編集して保存できます。

注釈

list_editable は、他のオプションと特定部分で相互関係にあります。以下のルールに注意してください。

  • list_editable 内のすべてのフィールドは list_display に含まれている必要があります。表示されていないフィールドは編集できないのです!
  • list_editablelist_display_links に同じフィールドを同時に指定することはできません -- 1 つのフィールドがフォームとリンクの両方になることはできないからです。

これらのルールを破った場合、バリデーションエラーとなります。

ModelAdmin.list_filter

admin のチェンジリストページの右サイドバーのフィルタを有効化するには、list_filter をセットしてください。

最もシンプルな list_filter はフィルタリングを有効にするフィールド名のリストまたはタプルを受け取りますが、より高度なオプションもいくつか用意されています。詳細は ModelAdmin リストフィルタ を参照してください。

ModelAdmin.list_max_show_all

"Show all" の admin チェンジリストページで表示するアイテム数をコントロールするには、list_max_show_all をセットしてください。チェンジリストページの "Show all" リンクは、この設定値以下の場合のみ表示されます。デフォルトでは 200 にセットされています。

ModelAdmin.list_per_page

ページ分割された admin のチェンジリストページに表示するアイテム数をコントロールするには、list_per_page をセットしてください。デフォルトでは 100 にセットされています。

admin のチェンジリストページでオブジェクトのリストを検索するときに select_related() を使用するよう Django に伝えるには、list_select_related をセットしてください。これにより多くのデータベースクエリを削減できます。

値は真偽値、リスト、タプルのどれかでなければなりません。デフォルトは False です。

値が True のとき、常に select_related() が呼ばれます。False のときは、ForeignKey が存在する場合 Django は list_display を参照して select_related() を呼び出します。

よりきめ細やかにコントロールする場合は、list_select_related の値にタプル (ないしリスト) を使用してください。空のタプルは、Django が select_related を一切呼び出さないようにします。他のタプルは、パラメータとして直接 select_related に渡されます。次に例を示します。

class ArticleAdmin(admin.ModelAdmin):
    list_select_related = ["author", "category"]

これは select_related('author', 'category') を呼び出します。

リクエストに基づいた動的な値を指定する場合は、get_list_select_related() メソッドを実装できます。

注釈

ModelAdminselect_related() がチェンジリストの QuerySet で既に呼び出されていた場合、この属性を無視します。

ModelAdmin.ordering

Django の admin ビューでオブジェクトのリストをどのようにソートするかを指定するには、 ordering をセットしてください。モデルの ordering パラメータと同じフォーマットでリストかタプルを与えてください。

指定がない場合、Django admin はモデルのデフォルトの並び順を使用します。

動的なソートを指定する場合 (例えばユーザーや言語に応じて変更する場合など)、get_ordering() メソッドを実装できます。

並べ替えやソートに伴うパフォーマンス上の注意

全体のソートのための単一もしくは unique together フィールド指定をチェンジリストが見つけられない場合、チェンジリストは pk をチェンジリストに追加します。これは結果の決定論的なソートを保証するためです。

たとえば、デフォルトのソートが一意でない name フィールドによって実行される場合、チェンジリストは namepk でソートされます。テーブルのレコード数が多く、 namepk のインデックスがない場合は、パフォーマンスの低下を招きます。

ModelAdmin.paginator

ページ分割に使われる paginator クラスです。デフォルトでは django.core.paginator.Paginator が使われます。カスタムの paginator クラスが django.core.paginator.Paginator と同じコンストラクタインターフェースを持たない場合、ModelAdmin.get_paginator() に対する実装も行う必要があります。

ModelAdmin.prepopulated_fields

prepopulated_fields を、フィールド名と事前入力するフィールドをマッピングした辞書に設定します。

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

設定された場合、指定されたフィールドは割り当てられたフィールドから入力するために JavaScript を使用します。この機能の主な用途は、1つ以上の他のフィールドから SlugField フィールドの値を自動的に生成することです。生成される値はソースフィールドの値を連結し、その結果を有効なスラグに変換することで生成されます (たとえば、ダッシュをスペースに置き換えたり、ASCII 文字を小文字にしたりします)。

事前入力されたフィールドは値が保存された後に JavaScript によって変更されることはありません。通常、スラグが変更されることは望ましくありません (スラグがオブジェクトで使用されている場合、オブジェクトの URL が変更されることになります)。

prepopulated_fieldsDateTimeFieldForeignKeyOneToOneFieldManyToManyField フィールドを受け入れません。

ModelAdmin.preserve_filters

デフォルトでは、オブジェクトを作成、編集、削除しても、適用されたフィルタはリストビューに保存されます。この属性を False に設定することで、フィルタをクリアできます。

ModelAdmin.show_facets
New in Django 5.0.

管理画面のチェンジリストのフィルタにファセット数を表示するかどうかを制御します。デフォルトは ShowFacets.ALLOW です。

表示されている場合、ファセット数は現在適用されているフィルタに合わせて更新されます。

class ShowFacets
New in Django 5.0.

ModelAdmin.show_facets に指定できる値の Enum。

ALWAYS

常にファセット数を表示します。

ALLOW

クエリ文字列パラメータ _facets が指定された場合に、ファセット数を表示します。

NEVER

ファセット数を表示しません。

show_facets に必要な ShowFacets の値を指定します。例えば、クエリパラメータを指定することなく常にファセット数を表示したい場合:

from django.contrib import admin


class MyModelAdmin(admin.ModelAdmin):
    ...
    # Have facets always shown for this model admin.
    show_facets = admin.ShowFacets.ALWAYS

ファセットを使う場合のパフォーマンス上の注意

ファセットフィルタを有効にすると、管理画面のチェンジリストページのクエリ数がフィルタの数だけ増えます。これらのクエリは、特に大きなデータセットの場合、パフォーマンスの問題を引き起こすかもしれません。このような場合は、 show_facetsShowFacets.NEVER に設定して、ファセットを完全に無効にするのが適切でしょう。

ModelAdmin.radio_fields

デフォルトでは、ForeignKeychoices がセットされたフィールドに対して、Django の admin はセレクトボックスのインターフェース (<select>) を使用します。フィールドが radio_fields に指定された場合、Django は代わりに ラジオボタンのインターフェースを使用します。groupPerson モデルの ForeignKey だと仮定すると、次のようになります。

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

django.contrib.admin モジュールから HORIZONTALVERTICAL のどちらを使用するか選択してください。

ForeignKey ないし choices がセットされたフィールド以外は、radio_fields に含めないでください。

ModelAdmin.autocomplete_fields

autocomplete_fields は、Select2 オートコンプリート入力に変更したい ForeignKey ないし ManyToManyField フィールドのリストです。

デフォルトでは、これらのフィールドに対して admin はセレクトボックスのインターフェース (<select>) を使用します。ドロップダウン内に表示する関係インスタンスをすべて選択するオーバーヘッドから逃れたいこともあるでしょう。

Select2 入力はデフォルトの入力と似た見た目ですが、非同期的にオプションを読み込む検索機能を持っています。こちらの方が高速で、特に関係モデルに多くのインスタンスがある場合にはユーザーフレンドリーです。

オートコンプリート検索はリレーション先オブジェクトの ModelAdmin を使用するため、ModelAdminsearch_fields を定義する必要があります。

認可されていないデータが漏洩されるのを防ぐため、オートコンプリートを使うには、ユーザーは必ずリレーション先オブジェクトに対する viewchange 権限を持っていなければなりません。

結果のソートおよびページ分割は、関係する ModelAdminget_ordering()get_paginator() メソッドでコントロールします。

以下の例では、ChoiceAdmin フィールドは Question への ForeignKey に対するオートコンプリートフィールドを持ちます。結果は question_text フィールドによりフィルタされ、また date_created フィールドにより並べ替えられます:

class QuestionAdmin(admin.ModelAdmin):
    ordering = ["date_created"]
    search_fields = ["question_text"]


class ChoiceAdmin(admin.ModelAdmin):
    autocomplete_fields = ["question"]

巨大なデータセットに対するパフォーマンス上の注意

ModelAdmin.ordering を使った並べ替えは、巨大なクエリセットは遅くなるため、パフォーマンスの問題の原因となります。

また、検索フィールドがデータベースによるインデックス化がされていないフィールドを含む場合、巨大なテーブルでは貧弱なパフォーマンスしか発揮できなくなってしまいます。

このような場合は、フルテキストのインデックスサーチを使用した独自の ModelAdmin.get_search_results() 実装を記述するのがよいでしょう。

また、デフォルトの paginator は常に count() を発行するため、巨大なテーブルでは Paginator を変更するのがお勧めです。例えば、Paginator.count プロパティのデフォルトの実装をオーバーライドできます。

ModelAdmin.raw_id_fields

デフォルトでは、ForeignKey のフィールドに対して Django の admin はセレクトボックスのインターフェース (<select>) を使用します。ドロップダウン内に表示する関係インスタンスをすべて選択するオーバーヘッドから逃れたいこともあるでしょう。

raw_id_fields は、ForeignKeyManyToManyField に対する Input ウィジェットを適用したいフィールドのリストです:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ["newspaper"]

raw_id_fields Input ウィジェットには、ForeignKey の場合はプライマリキーを、ManyToManyField の場合はカンマで区切った値のリストを入力します。raw_id_fields ウィジェットには、ユーザーが値を検索および選択できるよう、隣にルーペボタンがあります:

../../../_images/raw_id_fields.png
ModelAdmin.readonly_fields

デフォルトでは、すべてのフィールドが編集可能となっています。このオプションに含まれるフィールド (listtuple で指定します) は、データをそのまま表示するだけで編集できなくなります。また、追加と編集に使われる ModelForm からも除外されます。 ModelAdmin.fieldsModelAdmin.fieldsets を指定した場合、read-only のフィールドは表示のために存在している必要があります (存在しなければ無視されます)。

ModelAdmin.fieldsModelAdmin.fieldsets で明示的に並び順を定義しないで readonly_fields を使った場合、これらのフィールドはすべての編集可能なフィールドの後に表示されます。

read-only のフィールドはモデルのフィールドからデータを表示するだけではなく、モデルや ModelAdmin クラス自身のメソッドの出力を表示させることもできます。これは ModelAdmin.list_display の挙動に似ています。これにより、編集中のオブジェクトのステータスのフィードバックを admin インターフェースに与えることができるようになります。たとえば:

from django.contrib import admin
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe


class PersonAdmin(admin.ModelAdmin):
    readonly_fields = ["address_report"]

    # description functions like a model field's verbose_name
    @admin.display(description="Address")
    def address_report(self, instance):
        # assuming get_full_address() returns a list of strings
        # for each line of the address and you want to separate each
        # line by a linebreak
        return format_html_join(
            mark_safe("<br>"),
            "{}",
            ((line,) for line in instance.get_full_address()),
        ) or mark_safe("<span class='errors'>I can't determine this address.</span>")
ModelAdmin.save_as

admin のチェンジーフォームで "新規に保存" 機能を有効化するには save_as をセットしてください。

通常、オブジェクトには 3 つの保存オプションがあります: "保存"、"保存して編集を続ける"、"保存して 1 つ追加" です。save_asTrue の場合、"保存して 1 つ追加" が "新規に保存" ボタンに変更され、既存のオブジェクトを変更するのではなく (新しい ID) で新規のオブジェクトが作成されるようになります。

デフォルトでは save_asFalse にセットされています。

ModelAdmin.save_as_continue

save_as=True のとき、新規オブジェクトを保存した後のデフォルトのリダイレクト先はそのオブジェクトの変更ビューです。save_as_continue=False にセットすると、リダイレクト先がチェンジリストビューになります。

デフォルトでは save_as_continueTrue にセットされています。

ModelAdmin.save_on_top

admin のチェンジフォームの上部に保存ボタンを追加するには save_on_top をセットしてください。

通常、保存ボタンはフォームの下部のみに表示されます。save_on_top をセットすると、ボタンは上部と下部の両方に表示されるようになります。

デフォルトでは save_on_topFalse にセットされています。

ModelAdmin.search_fields

admin のチェンジリストページで検索ボックスを有効化するには search_fields をセットしてください。セットするのはフィールド名のリストで、ここで指定したフィールドはテキストボックス内での検索クエリの対象となります。

指定するフィールドの種類は、CharFieldTextField といったテキストフィールドである必要があります。ルックアップ API の "follow" 記法を使えば ForeignKeyManyToManyField をルックアップすることもできます。

search_fields = ["foreign_key__related_fieldname"]

たとえば、著者の情報を持つブログエントリーの場合、以下の定義により、著者のメールアドレスによるブログエントリーの検索が可能となります。

search_fields = ["user__email"]

検索ボックスで検索が行われるとき、Django は検索クエリを単語に分割し、(icontains ルックアップを使って) 大文字と小文字を区別しない各単語を含むオブジェクトを返します。各単語は最低 1 つの search_fields に含まれている必要があります。例えば、search_fields['first_name', 'last_name'] にセットされ、ユーザーが john lennon と検索した場合、Django は SQL の WHERE 節と同等の検索を実行します。

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

検索クエリには空白を含む引用句を含めることができます。たとえば、ユーザが "john winston"'john winston' を検索した場合、 Django はこの SQL の WHERE 句と等価な処理を行います。

WHERE (first_name ILIKE '%john winston%' OR last_name ILIKE '%john winston%')

もし icontains ルックアップを使用したくない場合は、フィールドに追加することで任意のルックアップを使用できます。例えば、search_fields['first_name__exact'] に設定することで、exact を使用できます。

いくつかの (古い) ショートカットを使って、フィールドルックアップを指定することもできます。以下の文字で search_fields 内のフィールドにプレフィックスを追加できます。これはフィールドに __<lookup> を追加するのと同等です。

プレフィックス ルックアップ
^ istartswith
= iexact
@ search
None icontains

検索方法をカスタムする必要がある場合は、ModelAdmin.get_search_results() を使って追加的もしくは代替の検索方法を提供できます。

ModelAdmin.search_help_text

search_help_text には検索ボックスの下に表示される説明文を指定します。

ModelAdmin.show_full_result_count

フィルタリングされた admin ページにオブジェクトのカウント (例: 99 results (103 total)) を表示するかどうかをコントロールするには、show_full_result_count をセットしてください。False にセットすると、代わりに 99 results (Show all) のような文字列が表示されるようになります。

デフォルトの show_full_result_count=True は、テーブル内の全アイテムをカウントするクエリを発行するため、多くの行を含むテーブルではパフォーマンス低下の原因となります。

ModelAdmin.sortable_by

デフォルトでは、チェンジリストページでは list_display で指定された全てのモデルフィールド (および display() デコレータの ordering 引数を使用する呼び出し可能オブジェクト、または admin_order_field 属性を持つ呼び出し可能オブジェクト) によるソートが可能です。

特定のカラムでのソートを無効化したい場合、 sortable_bylist_display サブセットのコレクション (例: listtupleset) をセットしてください。空のコレクションを指定すると、すべてのカラムでソート不可となります。

リストを動的に指定する必要があるときは、代わりに get_sortable_by() メソッドを実装してください。

ModelAdmin.view_on_site

"サイトで見る" リンクを表示するか否かをコントロールするには、view_on_site をセットしてください。このリンクは保存されたオブジェクトを表示できる URL に誘導します。

値は、真偽値か呼び出し可能オブジェクトで指定します。True (デフォルトです) の場合、オブジェクトの get_absolute_url() メソッドが使われ、URLが生成されます。

モデルが get_absolute_url() メソッドを持っていても "サイトで見る" ボタンを表示したくない場合は、view_on_siteFalse をセットしてください:

from django.contrib import admin


class PersonAdmin(admin.ModelAdmin):
    view_on_site = False

呼び出し可能オブジェクトの場合、引数にモデルのインスタンスを受け入れます。例えば:

from django.contrib import admin
from django.urls import reverse


class PersonAdmin(admin.ModelAdmin):
    def view_on_site(self, obj):
        url = reverse("person-detail", kwargs={"slug": obj.slug})
        return "https://example.com" + url

カスタムテンプレートのオプション

admin テンプレートをオーバーライドする セクションでは、デフォルトの admin テンプレートをオーバーライドないし拡張する方法を説明しています。ModelAdmin ビューで使用されるデフォルトのテンプレートをオーバーライドするには、以下のオプションを使用してください:

ModelAdmin.add_form_template

カスタムンテンプレートの絶対パスで、add_view() で使われます。

ModelAdmin.change_form_template

カスタムンテンプレートの絶対パスで、change_view() で使われます。

ModelAdmin.change_list_template

カスタムンテンプレートの絶対パスで、changelist_view() で使われます。

ModelAdmin.delete_confirmation_template

カスタムンテンプレートの絶対パスで、1 つ以上のオブジェクトを削除するときに確認ページを表示するために、delete_view() で使われます。

ModelAdmin.delete_selected_confirmation_template

カスタムンテンプレートの絶対パスで、1 つ以上のオブジェクトを削除するときに確認ページを表示するために、delete_selected アクションメソッドで使われます。アクションのドキュメント を参照してください。

ModelAdmin.object_history_template

カスタムンテンプレートの絶対パスで、history_view() で使われます。

ModelAdmin.popup_response_template

カスタムンテンプレートの絶対パスで、response_add()response_change()response_delete() の 3 つで使われます。

ModelAdmin のメソッド

警告

ModelAdmin.save_model()ModelAdmin.delete_model() をオーバーライドするときは、オブジェクトの保存や削除の処理を記述する必要があります。これは、制限を設けるためではなく、追加的な操作を可能にするための仕様です。

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

save_model メソッドには、HttpRequest、モデルのインスタンス、ModelForm のインスタンス、追加か変更かを表す真偽値が渡されます。このメソッドをオーバーライドすると、保存の前後に操作を追加できます。super().save_model() を呼び出して、Model.save() を使ってオブジェクトを保存してください。

例えば、保存前にオブジェクトに request.user を追加するには:

from django.contrib import admin


class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super().save_model(request, obj, form, change)
ModelAdmin.delete_model(request, obj)

delete_model には、HttpRequest とモデルのインスタンスが渡されます。このメソッドをオーバーライドすると、削除の前後に操作を追加できます。super().delete_model() を呼び出して、Model.delete() を使ってオブジェクトを削除してください。

ModelAdmin.delete_queryset(request, queryset)

delete_queryset() には、HttpRequest と削除するオブジェクトの QuerySet が渡されます。このメソッドをオーバーライドすると、"選択したオブジェクトの削除" アクション に対する削除のプロセスをカスタムできます。

ModelAdmin.save_formset(request, form, formset, change)

save_formset メソッドには、HttpRequest、親 ModelForm のインスタンス、親オブジェクトの追加か変更かを表す真偽値が与えられます。

たとえば、変更のあったフォームセットのモデルのインスタンスそれぞれに request.user を追加するには、次のようにします。

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

関連項目: フォームセット内のオブジェクトを保存する

ModelAdmin.get_ordering(request)

get_ordering メソッドは引数に request を取り、ordering のときと同じような listtuple を返すことが期待されます。次に例を示します。

class PersonAdmin(admin.ModelAdmin):
    def get_ordering(self, request):
        if request.user.is_superuser:
            return ["name", "rank"]
        else:
            return ["name"]
ModelAdmin.get_search_results(request, queryset, search_term)

get_search_results メソッドは、検索語と一致するオブジェクトを表示するための、オブジェクトのリストを修正します。リクエスト、現在のフィルタを適用するクエリセット、 ユーザーが入力した検索語を受け取ります。 検索を実行するために修正されたクエリセットと、結果に重複があるかどうかを表す真偽値を含むタプルを返します。

デフォルトの実装では、ModelAdmin.search_fields に含まれるフィールドを検索します。

このメソッドは、独自の検索方法でオーバーライドできます。例えば、数値のフィールドで検索したり、SolrHaystack といった外部のツールを使うことができます。独自の検索方法によって実装されたクエリセットの変更が結果に重複を生じさせるかを確認し、返値の 2 番目の要素に True を返す必要があります。

たとえば、nameage で検索するには、以下のように使います。

class PersonAdmin(admin.ModelAdmin):
    list_display = ["name", "age"]
    search_fields = ["name"]

    def get_search_results(self, request, queryset, search_term):
        queryset, may_have_duplicates = super().get_search_results(
            request,
            queryset,
            search_term,
        )
        try:
            search_term_as_int = int(search_term)
        except ValueError:
            pass
        else:
            queryset |= self.model.objects.filter(age=search_term_as_int)
        return queryset, may_have_duplicates

この実装は、数値フィールドに対して文字列比較を行う search_fields = ('name', '=age') に比べて、はるかに効率的です... たとえば PostgreSQL では ... OR UPPER("polls_choice"."votes"::text) = UPPER('4') となります。

save_related メソッドには、HttpRequest、親 ModelForm のインスタンス、インラインフォームセットのリスト、親の追加か変更かを表す真偽値が与えられます。このメソッドで、保存の前後に親に対するリレーション先オブジェクトに対する操作を追加できます。この時点では親オブジェクトとそのフォームはすでに保存されていることに注意してください。

ModelAdmin.get_autocomplete_fields(request)

get_autocomplete_fields() メソッドには、HttpRequest が渡され、上述の ModelAdmin.autocomplete_fields セクションで説明した通りオートコンプリートウィジェットで表示するフィールドの名前の listtuple を返すことが期待されます。

ModelAdmin.get_readonly_fields(request, obj=None)

get_readonly_fields メソッドには、HttpRequest と編集対象の obj (ないし新規追加用の None) が渡され、上述の ModelAdmin.readonly_fields セクションで説明した通り、読み取り専用で表示するフィールドの名前の listtuple を返すことが期待されます。

ModelAdmin.get_prepopulated_fields(request, obj=None)

get_prepopulated_fields メソッドには、HttpRequest と編集対象の obj (ないし新規追加用の None) が渡され、上述の ModelAdmin.prepopulated_fields セクションで説明した通り dictionary を返すことが期待されます。

ModelAdmin.get_list_display(request)

get_list_display メソッドには、HttpRequest が渡され、上述の ModelAdmin.list_display セクションで説明した通りチェンジリストビューで表示するフィールドの名前の listtuple を返すことが期待されます。

get_list_display_links メソッドには、HttpRequestModelAdmin.get_list_display() によって返された list ないし tuple が渡されます。上述の ModelAdmin.list_display_links セクションで説明した通り、チェンジリストで変更ビューにリンクを貼りたいフィールドの名前の listtuple、もしくは None を返すことが期待されます。

ModelAdmin.get_exclude(request, obj=None)

get_exclude メソッドには、HttpRequest と編集対象の obj (ないし新規追加用の None) が渡され、上述の ModelAdmin.exclude セクションで説明した通りフィールドのリストを返すことが期待されます。

ModelAdmin.get_fields(request, obj=None)

get_fields メソッドには、HttpRequest と編集対象の obj (ないし新規追加用の None) が渡され、上述の ModelAdmin.fields セクションで説明した通りフィールドのリストを返すことが期待されます。

ModelAdmin.get_fieldsets(request, obj=None)

get_fieldsets メソッドには、HttpRequest と編集対象の obj (ないし新規追加用の None) が渡され、2 値タプルのリストを返すことが期待されます。各 2 値タプルは、上述の ModelAdmin.fieldsets セクションで説明した通り admin のフォームページ上の <fieldset> を表します。

ModelAdmin.get_list_filter(request)

get_list_filter メソッドには、HttpRequest が渡され、list_filter 属性のときと同じ種類のシーケンス型を返すことが期待されます。

get_list_select_related メソッドには、HttpRequest が渡され、真偽値もしくは ModelAdmin.list_select_related と同様のリストを返す必要があります。

ModelAdmin.get_search_fields(request)

get_search_fields メソッドには、HttpRequest が渡され、search_fields 属性のときと同じ種類のシーケンス型を返すことが期待されます。

ModelAdmin.get_sortable_by(request)

get_list_display メソッドは HttpRequest を受け取り、チェンジリストページでソート可能なフィールドの名のコレクション (例: listtupleset) を返すことが期待されます。

デフォルトの実装では、セットされている場合は sortable_by を返します。セットされていなければ get_list_display() を参照します。

たとえば、1 つ以上のカラムを並び替え不可にするには:

class PersonAdmin(admin.ModelAdmin):
    def get_sortable_by(self, request):
        return {*self.get_list_display(request)} - {"rank"}
ModelAdmin.get_inline_instances(request, obj=None)

get_inline_instances メソッドは、編集中の HttpRequestobj (追加フォームの場合は None) を受け取り、以下の InlineModelAdmin セクションで説明されているように、InlineModelAdmin オブジェクトの list または tuple を返すことが期待されます。例えば、以下は追加、変更、削除、閲覧の権限に基づくデフォルトのフィルタリングなしでインラインを返す方法です:

class MyModelAdmin(admin.ModelAdmin):
    inlines = [MyInline]

    def get_inline_instances(self, request, obj=None):
        return [inline(self.model, self.admin_site) for inline in self.inlines]

このメソッドをオーバーライドする場合、返値となるインラインは inlines で定義したクラスのインスタンスにしてください。間違えると、リレーション先オブジェクトを追加する際に "Bad Request" が発生する可能性があります。

ModelAdmin.get_inlines(request, obj)

get_inlines メソッドは、編集対象の HttpRequestobj (追加フォームの場合は None) を受け取り、インラインのイテラブルを返すことが期待されます。 ModelAdmin.inlines で指定する代わりに、このメソッドをオーバーライドすることで、リクエストやモデルインスタンスに基づいて動的にインラインを追加できます。

ModelAdmin.get_urls()

ModelAdminget_urls メソッドは URLconf と同じようにその ModelAdmin で使用する URL を返します。 そのため、 URL ディスパッチャ で説明されているように、ビューの AdminSite.admin_view() ラッパーを使って拡張できます:

from django.contrib import admin
from django.template.response import TemplateResponse
from django.urls import path


class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super().get_urls()
        my_urls = [path("my_view/", self.admin_site.admin_view(self.my_view))]
        return my_urls + urls

    def my_view(self, request):
        # ...
        context = dict(
            # Include common variables for rendering the admin template.
            self.admin_site.each_context(request),
            # Anything else you want in the context...
            key=value,
        )
        return TemplateResponse(request, "sometemplate.html", context)

admin のレイアウトを使用したい場合、admin/base_site.html を extend してください:

{% extends "admin/base_site.html" %}
{% block content %}
...
{% endblock %}

注釈

self.my_view 関数が self.admin_site.admin_view でラップされていることに注意してください。これは重要であり、次の2つのことを保証します:

  1. パーミッションチェックが実行され、アクティブなスタッフユーザーだけがビューにアクセスできるようにします。
  2. django.views.decorators.cache.never_cache() デコレータはキャッシュを防ぐために適用され、返される情報が最新であることを保証します。

注釈

カスタムパターンが通常の管理URLよりも 前に 含まれていることに注意してください。管理URLのパターンは非常に許容範囲が広く、ほぼ何でも一致するため、通常はカスタムURLを組み込みのURLに前置したいと思うでしょう。

この例では、 my_view/admin/myapp/mymodel/my_view/ にアクセスされます (管理画面の URL が /admin/ に含まれていると仮定します)。

ページがキャッシュ可能で、それでもパーミッションチェックを行いたい場合は、 AdminSite.admin_view()cacheable=True 引数を渡します:

path("my_view/", self.admin_site.admin_view(self.my_view, cacheable=True))

ModelAdmin ビューは model_admin 属性を持ちます。その他の AdminSite ビューは admin_site 属性を持ちます。

ModelAdmin.get_form(request, obj=None, **kwargs)

admin の追加と変更のビューで使うための ModelForm クラスを返します。add_view()change_view() を参照してください。

基本の実装は modelform_factory() を使用して form をサブクラス化し、fieldsexclude といった属性によって修正されます。なので、例えばスーパーユーザーに対して追加的なフィールドを与えたい場合は、以下のように基本のフォームを変更できます:

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            kwargs["form"] = MySuperuserForm
        return super().get_form(request, obj, **kwargs)

ModelForm クラスを直接返すこともできます。

ModelAdmin.get_formsets_with_inlines(request, obj=None)

admin の追加や変更のビューで使用するための (FormSet, InlineModelAdmin) ペアを生成します。

たとえば、変更ビューのみで特定のインラインを表示したい場合、以下のように get_formsets_with_inlines をオーバーライドできます。

class MyModelAdmin(admin.ModelAdmin):
    inlines = [MyInline, SomeOtherInline]

    def get_formsets_with_inlines(self, request, obj=None):
        for inline in self.get_inline_instances(request, obj):
            # hide MyInline in the add view
            if not isinstance(inline, MyInline) or obj is not None:
                yield inline.get_formset(request, obj), inline
ModelAdmin.formfield_for_foreignkey(db_field, request, **kwargs)

ModelAdminformfield_for_foreignkey を使うと、ForignKey フィールドに対するデフォルトのフォームフィールドをオーバーライドできます。たとえば、ユーザーに基づいてこの ForeignKey フィールドに対するオブジェクトのサブセットを返すには:

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 super().formfield_for_foreignkey(db_field, request, **kwargs)

これは、HttpRequest インスタンスを使って Car ForeignKey フィールドをフィルタし、特定の User インスタンスが所有する car のみを表示します。

より複雑なフィルタを行うには、ModelForm.__init__() メソッドを使用することで、モデルの instance に基づいたフィルタを行うことができます (リレーションシップを扱うフィールド を参照してください)。たとえば:

class CountryAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["capital"].queryset = self.instance.cities.all()


class CountryAdmin(admin.ModelAdmin):
    form = CountryAdminForm
ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)

formfield_for_foreignkey メソッドと同じように、formfield_for_manytomany メソッドをオーバーライドすると ManyToMany に対するデフォルトのフォームフィールドを変更できます。たとえば、あるオーナーは複数の car を所有でき、また car は複数のオーナーに所有されるとすると(多対多の関係です) Car のフィールドをフィルタして特定の User が所有する car だけを表示できます:

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

formfield_for_foreignkeyformfield_for_manytomany メソッドと同じように、formfield_for_choice_field メソッドをオーバーライドすると選択肢として宣言されたフィールドに対するデフォルトのフォームフィールドを変更できます。 たとえば、スーパーユーザーと通常のスタッフで表示する選択肢を違うものにしたい場合、以下のように記述できます:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_choice_field(self, db_field, request, **kwargs):
        if db_field.name == "status":
            kwargs["choices"] = [
                ("accepted", "Accepted"),
                ("denied", "Denied"),
            ]
            if request.user.is_superuser:
                kwargs["choices"].append(("ready", "Ready for deployment"))
        return super().formfield_for_choice_field(db_field, request, **kwargs)

choices の制限

フォームフィールドにセットされたすべての choices 属性はそのフォームのフィールドのみに制限されます。モデル上の一致するフィールドに選択肢がセットされている場合、フォームに提供される選択肢はこの選択肢の有効なサブセットでなくてはなりません。そうでない場合、フォームの送信は、モデル自身の保存前のバリデーションで ValidationError とともに失敗します。

ModelAdmin.get_changelist(request, **kwargs)

リスト作成に使われる Changelist を返します。デフォルトでは、django.contrib.admin.views.main.ChangeList が使われます。このクラスを継承することで、リスト作成の動作を変更できます。

ModelAdmin.get_changelist_form(request, **kwargs)

チェンジリストページの Formset で使うための ModelForm クラスを返します。カスタムフォームを使うには、たとえば、次のようにします。

from django import forms


class MyForm(forms.ModelForm):
    pass


class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_form(self, request, **kwargs):
        return MyForm

Meta.model 属性を省略する

ModelFormMeta.model 属性を定義した場合、Meta.fields 属性 (ないし Meta.exclude 属性) も定義する必要があります。しかし ModelAdmin はこの値を無視して、ModelAdmin.list_editable 属性をオーバーライドします。最も簡単な解決方法は、Meta.model 属性を除外することです。これは ModelAdmin が使用する正しいモデルを提供するからです。

ModelAdmin.get_changelist_formset(request, **kwargs)

list_editable を使っている場合、チェンジリストページで使用するための ModelFormSet クラスを返します。カスタムのフォームセットを使うには、たとえば、次のようにします。

from django.forms import BaseModelFormSet


class MyAdminFormSet(BaseModelFormSet):
    pass


class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_formset(self, request, **kwargs):
        kwargs["formset"] = MyAdminFormSet
        return super().get_changelist_formset(request, **kwargs)
ModelAdmin.lookup_allowed(lookup, value, request)

チェンジリストページのオブジェクトは URL のクエリ文字列からルックアップしてフィルタすることができます。たとえば、list_filter はその仕組みで動作します。ルックアップは QuerySet.filter() (例 user__email=user@example.com) で使われているものと似ています。クエリ文字列のルックアップはユーザによって操作される可能性があるため、無許可のデータ漏洩を防ぐためにサニタイズする必要があります。

lookup_allowed() メソッドには、クエリ文字列 ('user__email' など)、対応する値 ('user@example.com' など)、リクエストからのルックアップパスが渡され、パラメータを使用したチェンジリストの QuerySet のフィルタリングが許可されているかどうかを示す真偽値を返します。 lookup_allowed()False を返した場合、 DisallowedModelAdminLookup (SuspiciousOperation のサブクラス) が発生します。

デフォルトでは、 lookup_allowed() はモデルのローカルフィールド、 list_filter で使用されるフィールドパス (ただし、 get_list_filter() からのパスは使用できません)、 limit_choices_toraw_id_fields で正しく機能するために必要なルックアップへのアクセスを許可します。

ModelAdmin サブクラスで許可されるルックアップをカスタマイズするには、このメソッドをオーバーライドします。

Changed in Django 5.0:

request 引数が追加されました。

ModelAdmin.has_view_permission(request, obj=None)

obj の閲覧が許可されている場合は True を、そうでなければ False を返します。obj が None の場合、この種類のオブジェクトの閲覧が一般的に許可されているかどうかを表すよう、TrueFalse を指定します (たとえば、False は現在のユーザーがこの種類のすべてのオブジェクトを閲覧できないことを意味します)。

デフォルトの実装では、ユーザーが "change" か "view" 権限を持っていれば True を返します。

ModelAdmin.has_add_permission(request)

オブジェクトの追加が許可されていれば True を、そうでなければ False を返します。

ModelAdmin.has_change_permission(request, obj=None)

obj の編集が許可されている場合は True を、そうでなければ False を返します。objNone の場合、この種類のオブジェクトの編集が一般的に許可されているかどうかを表すよう、TrueFalse を指定します (たとえば、False は現在のユーザーがこの種類のすべてのオブジェクトを編集できないことを意味します)。

ModelAdmin.has_delete_permission(request, obj=None)

obj の削除が許可されている場合は True を、そうでなければ False を返します。objNone の場合、この種類のオブジェクトの削除が一般的に許可されているかどうかを表すよう、TrueFalse を指定します (たとえば、False は現在のユーザーがこの種類のすべてのオブジェクトを削除できないことを意味します)。

ModelAdmin.has_module_permission(request)

admin のインデックスページでモジュールを表示し、そのモジュールへのアクセスを許可する場合は True を、そうでなければ False を返します。デフォルトでは User.has_module_perms() を使用します。 オーバーライドしても閲覧、追加、変更、削除のアクセス権は制限しません。アクセス権の制限には has_view_permission()has_add_permission()has_change_permission()has_delete_permission() を使用してください。

ModelAdmin.get_queryset(request)

ModelAdminget_queryset メソッドは admin サイトで編集可能なモデルインスタンスのすべての QuerySet を返します。このメソッドをオーバーライドする場面の 1 つは、ログイン中のユーザーが所有するオブジェクトを表示することです:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)
ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False)

django.contrib.messages バックエンドを使ってユーザーにメッセージを送ります。カスタムの ModelAdmin の例 を参照してください。

キーワード引数を使うと、メッセージレベルを変更したり、余分な CSS タグを追加したり、 contrib.message フレームワークがインストールされていない場合にサイレントエラーにしたりすることができます。これらのキーワード引数は django.contrib.messages.add_message() の引数と同じです。詳しくはその関数のドキュメントを参照してください。違いの一つは、レベルを整数/定数の他に文字列ラベルとして渡せる点です。

ModelAdmin.get_paginator(request, queryset, per_page, orphans=0, allow_empty_first_page=True)

このビューで使用する paginator のインスタンスを返します。デフォルトでは paginator のインスタンスを返します。

ModelAdmin.response_add(request, obj, post_url_continue=None)

add_view() ステージに対する HttpResponse を決定します。

response_add は、admin フォームが送信され、オブジェクトとすべての関係インスタンスが作成および保存された直後に呼び出されます。オーバーライドすることで、オブジェクトが作成された後のデフォルトの動作を変更できます。

ModelAdmin.response_change(request, obj)

change_view() ステージに対する HttpResponse を決定します。

response_change は、admin フォームが送信され、オブジェクトとすべての関係インスタンスが保存された直後に呼び出されます。オーバーライドすることで、オブジェクトが変更された後のデフォルトの動作を変更できます。

ModelAdmin.response_delete(request, obj_display, obj_id)

delete_view() ステージに対する HttpResponse を決定します。

response_delete は、オブジェクトが削除された後に呼び出されます。オーバーライドすることで、オブジェクトが削除された後のデフォルトの動作を変更できます。

obj_display は削除されたオブジェクトの名前を表す文字列です。

obj_id は削除するオブジェクトを取得するために使用するシリアライズされた識別子です。

ModelAdmin.get_formset_kwargs(request, obj, inline, prefix)

フォームセットのコンストラクタに渡されるキーワード引数をカスタマイズするためのフックです。たとえばフォームセットのフォームに request を渡すには:

class MyModelAdmin(admin.ModelAdmin):
    def get_formset_kwargs(self, request, obj, inline, prefix):
        return {
            **super().get_formset_kwargs(request, obj, inline, prefix),
            "form_kwargs": {"request": request},
        }

また、フォームセットのフォームに initial を指定するためにも使用できます。

ModelAdmin.get_changeform_initial_data(request)

admin の変更フォームの初期データに対するフックです。デフォルトでは、フィールドには GET パラメータで初期値が与えられます。たとえば、 ?name=initial_valuename フィールドの初期値を initial_value にセットします。

このメソッドは、{'fieldname': 'fieldval'} という形式のディクショナリを返します:

def get_changeform_initial_data(self, request):
    return {"name": "custom_initial_value"}
ModelAdmin.get_deleted_objects(objs, request)

delete_view() と "delete selected" アクション の削除処理をカスタマイズするフックです。

引数 objs は削除するオブジェクト (QuerySet またはモデルインスタンスのリスト) の同型イテラブルで、 requestHttpRequest です。

このメソッドは (deleted_objects, model_count, perms_needed, protected) の4タプルを返さなければなりません。

deleted_objects は削除されるすべてのオブジェクトを表す文字列のリストです。削除されるオブジェクトにリレーション先オブジェクトがある場合、リストはネストされ、それらのリレーション先オブジェクトも含まれます。リストはテンプレート内で unordered_list フィルタを使ってフォーマットされます。

model_count は各モデルの verbose_name_plural と削除されるオブジェクトの数をマッピングした辞書です。

perms_needverbose_name のセットで、ユーザが削除する権限を持っていないモデルです。

protected は削除できない保護されたリレーション先オブジェクトを表す文字列のリストです。このリストはテンプレートに表示されます。

その他のメソッド

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

モデルインスタンスの追加ページに対する Django のビューです。以下のノートを参照してください。

ModelAdmin.change_view(request, object_id, form_url='', extra_context=None)

モデルインスタンスの編集ページに対する Django のビューです。以下のノートを参照してください。

ModelAdmin.changelist_view(request, extra_context=None)

モデルインスタンスの変更リスト(チェンジリスト)およびアクションページに対する Django のビューです。以下のノートを参照してください。

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

モデルインスタンスの削除の確認ページに対する Django のビューです。以下のノートを参照してください。

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

与えられたモデルのインスタンスに対する修正履歴を表示するページに対する Django のビューです。

前の節で詳しく説明したフック型の ModelAdmin メソッドとは異なり、これら 5 つのメソッドは、実際には admin アプリケーションの URL ディスパッチハンドラから Django ビューとして呼び出され、モデルインスタンスの CRUD 操作を扱うページをレンダリングするように設計されています。そのため、これらのメソッドを完全にオーバーライドすると、 admin アプリケーションの動作が大きく変わってしまいます。

これらのメソッドをオーバーライドする一般的な理由の 1 つは、ビューをレンダリングするテンプレートに提供されるコンテキスト・データを補強することです。以下の例では、change ビューがオーバーライドされ、レンダリングされるテンプレートに、他の方法では利用できないマッピング・データが提供されます:

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):
        # ...
        pass

    def change_view(self, request, object_id, form_url="", extra_context=None):
        extra_context = extra_context or {}
        extra_context["osm_data"] = self.get_osm_info()
        return super().change_view(
            request,
            object_id,
            form_url,
            extra_context=extra_context,
        )

これらのビューは TemplateResponse インスタンスを返し、レンダリング前のレスポンスデータを簡単にカスタマイズできます。詳細は TemplateResponse のドキュメント を参照してください。

ModelAdmin アセットの定義

ビューを追加したり変更したりするために、CSS や JavaScript を追加したいことがあるかもしれません。そういうときには ModelAdminMedia インナークラスを使用します:

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

staticfiles アプリ は、すべてのアセットのパスの前に STATIC_URL (STATIC_URLNone の場合は MEDIA_URL) を付与します。 フォーム上の通常のアセット定義 と同じルールが適用されます。

jQuery

Django admin の JavaScript は jQuery ライブラリを使用します。

ユーザが提供するスクリプトやライブラリとの衝突を避けるため、 Django の jQuery (version 3.7.1) は django.jQuery という名前空間になっています。自分の admin JavaScript で jQuery を使いたい場合、別のコピーを入れなくても、 django.jQuery オブジェクトをチェンジリストやadd/edit ビューで使用できます。また、 django.jQuery に依存する独自の管理フォームやウィジェットは、 フォーム メディア アセットの宣言 の際に js=['admin/js/jquery.init.js', …] を指定しなければなりません。

Changed in Django 4.2:

jQuery が 3.6.0 から 3.6.4 にアップグレードされました。

Changed in Django 5.0:

jQueryが 3.6.4 から 3.7.1 にアップグレードされました。

ModelAdmin クラスはデフォルトで jQuery を要件とするので、特別なニーズがない限り jQuery をメディアリソースの ModelAdmin のリストに追加する必要はありません。たとえば、jQuery ライブラリがグローバルな名前空間を持つ必要がある場合 (たとえば、サードパーティの jQuery プラグインを使用する場合など)、もしくは jQuery の新しいバージョンを使いたい場合には、自分自身でコピーを用意する必要があります。

Django には、非圧縮と 'minified' のバージョンのjQuery があり、それぞれ jquery.jsjquery.min.js となっています。

ModelAdminInlineModelAdmin には、フォームやフォームセットのJavaScriptファイルへのパスを格納する Media オブジェクトのリストを返す media プロパティがあります。 DEBUGTrue の場合、 jquery.js を含む様々な JavaScript ファイルの圧縮されていないバージョンを返します。そうでない場合は、 "minify" されたバージョンを返します。

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

また、管理画面でデータのカスタムバリデーションを追加することもできます。自動管理インターフェイスは django.forms を再利用し、 ModelAdmin クラスは独自のフォームを定義する機能を提供します:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

MyArticleAdminForm は必要な場所をインポートすればどこでも定義できます。これでフォームの中で任意のフィールドに対して独自のカスタムバリデーションを追加できます:

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

ここで ModelForm を使用することは重要です。そうしないと問題が発生する可能性があります。 カスタムバリデーション に関する フォーム のドキュメント、そしてより具体的には モデルフォームのバリデーションに関する注意事項 を参照してください。

InlineModelAdmin オブジェクト

class InlineModelAdmin
class TabularInline
class StackedInline

admin インターフェースには、親モデルと同じページでモデルを編集する機能があります。この機能をインラインと呼びます。以下の 2 つのモデルがあるとしましょう:

from django.db import models


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


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

author のページで、author が書いた book を編集できます。ModelAdmin.inlines 内でモデルに対するインラインを追加します:

from django.contrib import admin


class BookInline(admin.TabularInline):
    model = Book


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

Django には、以下の通り InlineModelAdmin のサブクラスが 2 つあります:

この 2 つの違いは、単にレンダリングするために使われるテンプレートの違いです。

InlineModelAdmin のオプション

InlineModelAdminModelAdmin と多くの機能を共有しており、さらにいくつかの独自の機能を有しています (共有の機能は実際には BaseModelAdmin 基底クラスで定義されています)。共有の機能は下記です:

InlineModelAdmin クラスは、以下を追加またはカスタマイズしています:

InlineModelAdmin.model

インラインが使用するモデルです。これは必須です。

InlineModelAdmin.fk_name

モデルの外部キーの名前です。多くの場合、これは自動的に処理されますが、同じ親モデルに対して複数の外部キーがある場合には fk_name を明示的に指定する必要があります。

InlineModelAdmin.formset

これはデフォルトでは BaseInlineFormSet です。自分自身のフォームセットを使用すると、カスタマイズの幅が広がります。インラインは モデル フォームセット で構築されます。

InlineModelAdmin.form

form に対する値で、デフォルトは ModelForm です。これは、このインラインに対してフォームセットが生成される際に inlineformset_factory() に渡されるものです。

警告

InlineModelAdmin フォーム用のカスタムバリデーションを書く際には、親モデルの機能に依存したバリデーションを書くことに注意してください。親モデルがバリデーションに失敗した場合、 ModelForm の検証 (バリデーション) の警告に記述されているように、一貫性のない状態で放置される可能性があります。

InlineModelAdmin.classes

インラインに対してレンダリングするフォームセットに適用する、追加的な CSS クラスのリストないしタプルです。デフォルトは None です。fieldsets で設定したクラスと同様に、collapse クラスを伴うインラインは最初は折りたたまれており小さな "show" リンクを持ちます。

InlineModelAdmin.extra

フォームセットが初期のフォームに加えて表示する追加的なフォームの数をコントロールします。デフォルトは 3 です。詳しくは フォームセットのドキュメント を参照してください。

JavaScript が有効なブラウザを使っているユーザーに対しては、"1 つ追加" のリンクが提供され、extra 引数の結果提供されるインラインに加えていくつでもインラインを追加できます。

現在表示されているフォームの数が max_num を超えている場合、またはユーザーが JavaScript を有効にしていない場合、ダイナミックリンクは表示されません。

InlineModelAdmin.get_extra() でも追加フォームの数をカスタマイズできます。

InlineModelAdmin.max_num

インラインに表示するフォームの最大数をコントロールします。オブジェクトの数と直接関係はありませんが、値が小さい場合には関係する可能性があります。詳しくは 編集可能なオブジェクトの数を制限する を参照してください。

InlineModelAdmin.get_max_num() でも追加フォームの最大数をカスタマイズできます。

InlineModelAdmin.min_num

インラインに表示するフォームの最小数をコントロールします。詳しくは modelformset_factory() を参照してください。

InlineModelAdmin.get_min_num() でも追加フォームの最小数をカスタマイズできます。

InlineModelAdmin.raw_id_fields

デフォルトでは、ForeignKey のフィールドに対して Django の admin はセレクトボックスのインターフェース (<select>) を使用します。ドロップダウン内に表示する関係インスタンスをすべて選択するオーバーヘッドから逃れたいこともあるでしょう。

raw_id_fields は、ForeignKeyManyToManyField に対する Input ウィジェットを適用したいフィールドのリストです:

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ["pages"]
InlineModelAdmin.template

ページ上でインラインをレンダリングするのに使われるテンプレートです。

InlineModelAdmin.verbose_name

モデル内部の Meta クラスの verbose_name のオーバーライドです。

InlineModelAdmin.verbose_name_plural

モデル内部の Meta クラスの verbose_name_plural をオーバーライドします。これが与えられず、 InlineModelAdmin.verbose_name が定義されている場合、 Django は InlineModelAdmin.verbose_name + 's' を使用します。

InlineModelAdmin.can_delete

インライン内でインラインオブジェクトを削除可能にするかどうかを指定します。デフォルトは True です。

admin 内で変更可能なインラインオブジェクトをが変更フォームへのリンクを持つかどうかを指定します。デフォルトは False です。

InlineModelAdmin.get_formset(request, obj=None, **kwargs)

admin の追加/変更ビューで使用する BaseInlineFormSet クラスを返します。 obj は編集対象の親オブジェクト、または新しい親オブジェクトを追加する場合は None です。 ModelAdmin.get_formsets_with_inlines の例を参照してください。

InlineModelAdmin.get_extra(request, obj=None, **kwargs)

使用する追加インラインフォームの数を返します。デフォルトでは、InlineModelAdmin.extra 属性を返します。

プログラムに従って追加インラインフォームの数を決めたい場合、このメソッドをオーバーライドしてください。たとえば、モデルインスタンス (キーワード引数の obj で渡されています) に基づいて数を決められます:

class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

    def get_extra(self, request, obj=None, **kwargs):
        extra = 2
        if obj:
            return extra - obj.binarytree_set.count()
        return extra
InlineModelAdmin.get_max_num(request, obj=None, **kwargs)

使用する追加インラインフォームの最大数を返します。デフォルトでは、InlineModelAdmin.max_num 属性を返します。

プログラムに従ってインラインフォームの最大数を決めたい場合、このメソッドをオーバーライドしてください。たとえば、モデルインスタンス (キーワード引数の obj で渡されています) に基づいて最大数を決められます:

class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

    def get_max_num(self, request, obj=None, **kwargs):
        max_num = 10
        if obj and obj.parent:
            return max_num - 5
        return max_num
InlineModelAdmin.get_min_num(request, obj=None, **kwargs)

使用する追加インラインフォームの最小数を返します。デフォルトでは、InlineModelAdmin.min_num 属性を返します。

プログラムに従ってインラインフォームの最小数を決めたい場合、このメソッドをオーバーライドしてください。たとえば、モデルインスタンス (キーワード引数の obj で渡されています) に基づいて最小数を決められます:

InlineModelAdmin.has_add_permission(request, obj)

インラインオブジェクトの追加が許可されている場合 True を、そうでなければ False を返します。obj は編集される親オブジェクトか、新規追加の場合には None となります。

InlineModelAdmin.has_change_permission(request, obj=None)

インラインオブジェクトの編集が許可されている場合 True を、そうでなければ False を返します。obj は編集される親オブジェクトです。

InlineModelAdmin.has_delete_permission(request, obj=None)

インラインオブジェクトの削除が許可されている場合 True を、そうでなければ False を返します。obj は編集される親オブジェクトです。

注釈

InlineModelAdmin メソッドに渡される obj 引数は編集対象の親オブジェクト、または新しい親オブジェクトを追加する場合は None です。

同じ親モデルへの複数の外部キーを持つモデルを扱う

同じモデルに対する複数の外部キーを持つこともあり得ます。例として以下のモデルを見てみましょう:

from django.db import models


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

Person の admin の追加や変更ページでインラインを表示したい場合は、自動的に判別することができないため、外部キーを明示的に定義する必要があります:

from django.contrib import admin
from myapp.models import Friendship


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


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

多対多のモデルを扱う

デフォルトでは、多対多のリレーションに対する管理ウィジェットは、実際に ManyToManyField への参照を含むモデルに表示されます。 ModelAdmin の定義に応じて、モデル内の各多対多フィールドは標準のHTML <select multiple>, 水平または垂直フィルタ、または raw_id_fields ウィジェットによって表されます。しかし、これらのウィジェットをインラインで置き換えることもできます。

次のようなモデルがあるとします:

from django.db import models


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


class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, related_name="groups")

インラインを使用して多対多のリレーションを表示したい場合、リレーションシップに InlineModelAdmin オブジェクトを定義することで表示できます:

from django.contrib import admin


class MembershipInline(admin.TabularInline):
    model = Group.members.through


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


class GroupAdmin(admin.ModelAdmin):
    inlines = [
        MembershipInline,
    ]
    exclude = ["members"]

この例で注目すべき点は2つです。

まず、 MembershipInline クラスは Group.members.through を参照しています。 through 属性は多対多のリレーションを管理するモデルへの参照です。このモデルは、多対多のフィールドを定義したときに Django が自動的に作成します。

次に、 GroupAdmin は手動で members フィールドを除外する必要があります。Django は多対多のフィールドの管理ウィジェットを、リレーションを定義するモデル (この場合は Group) 上に表示します。インラインモデルを使って多対多のリレーションを表現したい場合は、 Django の admin に、このウィジェットを 表示しない ように指示しなければなりません。

このテクニックを使う場合、 m2m_changed シグナルはトリガーされないことに注意してください。これは、admin にとっては through は多対多のリレーションではなく、2つの外部キーフィールドを持つモデルに過ぎないからです。

その他の点では InlineModelAdmin は他のものと全く同じです。通常の ModelAdmin プロパティを使用して外観をカスタマイズできます。

多対多の中間モデルとともに使う

ManyToManyFieldthrough 引数で中間モデルを指定した場合、管理画面はデフォルトではウィジェットを表示しません。これは、その中間モデルの各インスタンスは、単一のウィジェットで表示できる以上の情報を必要とし、複数のウィジェットに必要なレイアウトは中間モデルによって異なるからです。

しかし、インラインで情報を編集できるようにしたいと思うでしょう。幸いなことに、インライン admin モデルでこれを実現できます。次のようなモデルがあるとします:

from django.db import models


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, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

この中間モデルを管理画面に表示するための最初のステップは Membership モデルのインラインクラスを定義することです:

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

この例では Membership モデルにデフォルトの InlineModelAdmin の値を使用し、追加の追加フォームを 1 つに制限しています。これは InlineModelAdmin クラスで利用可能なオプションを使ってカスタマイズできます。

次に PersonGroup モデルの管理ビューを作成します:

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


class GroupAdmin(admin.ModelAdmin):
    inlines = [MembershipInline]

最後に、 PersonGroup のモデルを管理サイトに登録します:

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

これであなたの管理サイトは Person または Group の詳細ページから Membership オブジェクトをインラインで編集できるように設定されました。

ジェネリックリレーションをインラインとして使う

ジェネリックリレーションを定義されたオブジェクトでインラインを使用することもできます。以下のようなモデルがあるとします:

from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models


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


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

Product の追加/変更ビューで Image インスタンスの編集や作成を可能にしたい場合、 admin によって提供される GenericTabularInlineGenericStackedInline (どちらも GenericInlineModelAdmin のサブクラス)を使用できます。これらはそれぞれ、インラインオブジェクトを表すフォームのための tabular 形式と stack 形式のビジュアルレイアウトを実装しており、ジェネリックでないものと同様です。これらは他のインラインと全く同じように動作します。この例のアプリのための admin.py では次のようにします:

from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline

from myapp.models import Image, Product


class ImageInline(GenericTabularInline):
    model = Image


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


admin.site.register(Product, ProductAdmin)

詳しくは contenttypes のドキュメント を参照してください。

admin テンプレートをオーバーライドする

admin モジュールが admin サイトの様々なページを生成するために使用するテンプレートの多くはオーバーライドできます。特定のアプリや特定のモデルのためにこれらのテンプレートの一部をオーバーライドすることもできます。

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

admin テンプレートファイルは django/contrib/admin/templates/admin ディレクトリにあります。

そのうちの一つ以上を上書きするには、まずプロジェクトの templates ディレクトリに admin ディレクトリを作成してください。これは DjangoTemplates バックエンドの DIRS オプションの TEMPLATES 設定で指定したディレクトリのどれでもかまいません。 'loaders' オプションをカスタマイズしている場合は、 'django.template.loaders.app_directories.Loader' の前に 'django.template.loaders.filesystem.Loader' が表示されていることを確認してください。そうすれば、 django.contrib.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 テンプレートをオーバーライドするか、それとも置き換えるか

管理画面のテンプレートはモジュール化されているため、通常はテンプレート全体を置き換える必要はありません。ほとんどの場合、変更する必要があるテンプレートのセクションだけをオーバーライドする方がよいでしょう。

上記の例の続きとして、Page モデルの History ツールの隣に新しいリンクを追加したいとします。 change_form.html を見ると、 object-tools-items ブロックをオーバーライドするだけでよいことがわかります。そこで、以下に新しい change_form.html の例を示します:

{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
    <li>
        <a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% translate "History" %}</a>
    </li>
    <li>
        <a href="mylink/" class="historylink">My Link</a>
    </li>
    {% if has_absolute_url %}
        <li>
            <a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% translate "View on site" %}</a>
        </li>
    {% endif %}
{% endblock %}

これで完了です!このファイルを templates/admin/my_app ディレクトリに置くと、my_app 内のすべてのモデルの変更フォームにリンクが表示されます。

アプリやモデルごとにオーバーライド可能なテンプレート

contrib/admin/templates/admin にある全てのテンプレートがアプリやモデルごとにオーバーライドできるわけではありません。以下のものは可能です:

  • actions.html
  • app_index.html
  • change_form.html
  • change_form_object_tools.html
  • change_list.html
  • change_list_object_tools.html
  • change_list_results.html
  • date_hierarchy.html
  • delete_confirmation.html
  • object_history.html
  • pagination.html
  • popup_response.html
  • prepopulated_fields_js.html
  • search_form.html
  • submit_line.html

この方法でオーバーライドできないテンプレートについては、 templates/admin ディレクトリに新しいバージョンを置くことで、プロジェクト全体でオーバーライドできます。これは特に独自の404ページや500ページを作成するのに便利です。

注釈

change_list_results.html のようないくつかの管理用テンプレートはカスタムインクルージョンタグのレンダリングに使用されます。これらはオーバーライドできますが、そのような場合、おそらく問題のタグの独自のバージョンを作成し、別の名前を付けた方が良いでしょう。そうすれば、選択的に使用できます。

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

インデックス、ログイン、ログアウトのテンプレートを変更したい場合は、独自の AdminSite インスタンス(下記参照)を作成し、 AdminSite.index_templateAdminSite.login_templateAdminSite.logout_template プロパティを変更した方が良いでしょう。

テーマのサポート

管理画面では、CSS 変数を使用して色とフォントを定義します。これにより、多くの個別の CSS ルールを上書きすることなくテーマを変更できます。たとえば、青の代わりに紫を使うには、以下のような admin/base.html テンプレートをプロジェクトに追加します。

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

{% block extrastyle %}{{ block.super }}
<style>
html[data-theme="light"], :root {
  --primary: #9774d5;
  --secondary: #785cab;
  --link-fg: #7c449b;
  --link-selected-fg: #8f5bb2;
}
</style>
{% endblock %}

CSS 変数のリストは django/contrib/admin/static/admin/css/base.css で定義されています。

prefers-color-scheme メディアクエリを尊重したダークモード変数は django/contrib/admin/static/admin/css/dark_mode.css で定義されています。これは {% block dark-mode-vars %} のドキュメントにリンクされています。

AdminSite オブジェクト

class AdminSite(name='admin')

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

デフォルトのadminサイトをカスタマイズしたい場合は、 オーバーライド することができます。

管理サイト AdminSite のインスタンスを作成する際には、コンストラクタの name 引数に一意なインスタンス名を指定できます。このインスタンス名はインスタンスを識別するために使用され、特に 管理用URL を逆引きするときに使用されます。インスタンス名を指定しなかった場合、デフォルトのインスタンス名 admin が使用されます。 AdminSite クラスをカスタマイズする例については AdminSite クラスのカスタマイズ を参照してください。

django.contrib.admin.sites.all_sites

WeakSet は全ての管理サイトのインスタンスを含んでいます。

AdminSite の属性

テンプレートは admin テンプレートをオーバーライドする で説明されているように、基本管理テンプレートを上書きしたり拡張したりすることができます。

AdminSite.site_header

各管理ページの上部に表示するテキストを <div> (文字列) で指定します。デフォルトでは "Django administration" です。

Changed in Django 5.0:

古いバージョンでは site_header<h1> タグを使用していました。

AdminSite.site_title

各管理ページの <title> の末尾に付けるテキスト (文字列)。デフォルトでは "Django site admin" です。

AdminSite.site_url

各管理ページの上部にある "サイトを見る "リンクのURL。デフォルトでは site_url/ です。リンクを削除するには None を指定してください。

サブパス上で動作しているサイトでは、 each_context() メソッドは現在のリクエストに request.META['SCRIPT_NAME'] が設定されているかどうかをチェックし、 site_url/ 以外の値が設定されていなければ、その値を使用します。

AdminSite.index_title

管理インデックスページのトップに表示するテキスト(文字列)。デフォルトでは "Site administration "です。

AdminSite.index_template

admin サイトのメインインデックスビューで使用されるカスタムテンプレートへのパス。

AdminSite.app_index_template

admin サイトのアプリ インデックスビューで使用されるカスタムテンプレートへのパス。

AdminSite.empty_value_display

admin サイトのチェンジリストで空の値を表示する際に使用する文字列。デフォルトはダッシュです。この値はフィールドに empty_value_display 属性を指定することで、 ModelAdmin ごとや ModelAdmin 内のカスタムフィールドごとにオーバーライドできます。例については ModelAdmin.empty_value_display を参照してください。

AdminSite.enable_nav_sidebar

大きな画面でナビゲーションサイドバーを表示するかどうかを決定する真偽値。デフォルトでは True に設定されています。

AdminSite.final_catch_all_view

認証されていないユーザーをログインページにリダイレクトさせる最終キャッチオールビューを管理画面に追加するかどうかを決定する真偽値。デフォルトでは True に設定されています。

警告

このビューはモデル列挙のプライバシーに関する潜在的な問題から保護するため、これを False に設定することは推奨されません。

AdminSite.login_template

admin サイトのログインビューで使用されるカスタムテンプレートへのパス。

AdminSite.login_form

admin サイトのログインビューで使用される AuthenticationForm のサブクラス。

AdminSite.logout_template

admin サイトのログアウトビューで使用されるカスタムテンプレートへのパス。

AdminSite.password_change_template

admin サイトのパスワード変更ビューで使用されるカスタムテンプレートへのパス。

AdminSite.password_change_done_template

adminサイトのパスワード変更完了ビューで使用されるカスタムテンプレートへのパス。

AdminSite のメソッド

AdminSite.each_context(request)

admin サイトの各ページのテンプレートコンテキストに置く変数の辞書を返します。

デフォルトで以下の変数と値が含まれています:

  • site_header: AdminSite.site_header

  • site_title: AdminSite.site_title

  • site_url: AdminSite.site_url

  • has_permission: AdminSite.has_permission()

  • available_apps: アプリケーションレジストリ から現在のユーザーが利用できるアプリケーションのリストです。リストの各エントリは以下のキーを持つアプリケーションを表す dict です:

    • app_label: アプリケーションのラベル
    • app_url: admin のアプリケーションインデックスの URL
    • has_module_perms: 現在のユーザーに対して、モジュールのインデックスページの表示とアクセスが許可されているかどうかを示す真偽値。
    • models: アプリケーションで利用可能なモデルのリスト。

    各 model は以下のキーを持つ dict です:

    • model: モデルクラス
    • object_name: モデルのクラス名
    • name: 複数形のモデル名
    • perms: add, change, delete, view のパーミッションをトラッキングする dict
    • admin_url: モデルの管理用チェンジリストのURL
    • add_url: 新しいモデルインスタンスを追加するための管理用URL
  • is_popup: 現在のページがポップアップウィンドウで表示されるかどうか

  • is_nav_sidebar_enabled: AdminSite.enable_nav_sidebar

  • log_entries: AdminSite.get_log_entries()

AdminSite.get_app_list(request, app_label=None)

アプリケーションレジストリ から、現在のユーザーが利用できるアプリケーションのリストを返します。オプションで app_label 引数を渡すことで、単一のアプリケーションの詳細を取得できます。リストの各エントリは以下のキーを持つアプリケーションを表す辞書です:

  • app_label: アプリケーションのラベル
  • app_url: admin のアプリケーションインデックスの URL
  • has_module_perms: 現在のユーザーに対して、モジュールのインデックスページの表示とアクセスが許可されているかどうかを示す真偽値。
  • models: アプリケーションで利用可能なモデルのリスト。
  • name: アプリケーションの名前

各 model は以下のキーを持つ辞書です:

  • model: モデルクラス
  • object_name: モデルのクラス名
  • name: 複数形のモデル名
  • perms: add, change, delete, view のパーミッションをトラッキングする dict
  • admin_url: モデルの管理用チェンジリストのURL
  • add_url: 新しいモデルインスタンスを追加するための管理用URL

アプリケーションとモデルのリストはそれらの名前によってアルファベット順にソートされます。このメソッドをオーバーライドして、管理インデックスページのデフォルトの並び順を変更できます。

AdminSite.has_permission(request)

指定された HttpRequest のユーザが admin サイトの少なくとも1つのページを閲覧する権限を持っている場合に True を返します。デフォルトは User.is_activeUser.is_staff の両方が True である必要があります。

AdminSite.register(model_or_iterable, admin_class=None, **options)

指定された model クラス (またはクラスのイテラブル) を指定された admin_class とともに登録します。admin_class はデフォルトで ModelAdmin (デフォルトの管理オプション) になります。キーワード引数 (たとえば list_display) が与えられた場合、それらは admin クラスのオプションとして適用されます。

モデルが抽象クラスの場合は ImproperlyConfigured を、モデルが既に登録されている場合は django.contrib.admin.exceptions.AlreadyRegistered を発生させます。

AdminSite.unregister(model_or_iterable)

指定されたモデルクラス(またはクラスのイテラブル)の登録を解除します。

モデルが登録されていない場合、 django.contrib.admin.exceptions.NotRegistered を発生させます。

AdminSite.get_model_admin(model)
New in Django 5.0.

与えられた model クラスの admin クラスを返します。モデルが登録されていない場合は django.contrib.admin.exceptions.NotRegistered を発生させます。

AdminSite.get_log_entries(request)
New in Django 5.0.

サイトインデックスページに表示される、関連する LogEntry インスタンスのクエリセットを返します。このメソッドは、他の条件でログエントリをフィルタするためにオーバーライドできます。

URLconf に AdminSite インスタンスをフックします。

Django admin のセットアップの最後のステップは、 AdminSite インスタンスを URLconf にフックすることです。指定した URL を AdminSite.urls メソッドで指定します。 include() を使う必要はありません。

このインスタンスでは、デフォルトの AdminSite インスタンス django.contrib.admin.site を URL /admin/ に登録します:

# urls.py
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path("admin/", admin.site.urls),
]

AdminSite クラスのカスタマイズ

カスタムの動作で独自の admin サイトを設定したい場合は、自由に AdminSite をサブクラス化し、好きなものをオーバーライドしたり追加したりすることができます。そして、 AdminSite サブクラスのインスタンスを作成し (他の Python クラスと同じようにインスタンスを作成します)、モデルや ModelAdmin サブクラスをデフォルトのサイトではなく、サブクラスに登録します。最後に、 myproject/urls.py を更新して、 AdminSite サブクラスを参照するようにします。

myapp/admin.py
from django.contrib import admin

from .models import MyModel


class MyAdminSite(admin.AdminSite):
    site_header = "Monty Python administration"


admin_site = MyAdminSite(name="myadmin")
admin_site.register(MyModel)
myproject/urls.py
from django.urls import path

from myapp.admin import admin_site

urlpatterns = [
    path("myadmin/", admin_site.urls),
]

自分の AdminSite インスタンスを使う場合、アプリごとの admin モジュールを全て myproject.admin モジュールにインポートする可能性が高いので、 admin モジュールを自動検出させたくないかも知れないことに注意してください。つまり、 INSTALLED_APPS 設定に 'django.contrib.admin' の代わりに 'django.contrib.admin.apps.SimpleAdminConfig' を記述する必要があります。

デフォルトの admin サイトをオーバーライドする

デフォルトの django.contrib.admin.site をオーバーライドするには、カスタム AppConfigdefault_site 属性に AdminSite サブクラスまたはサイトのインスタンスを返す呼び出し可能オブジェクトのドット区切りインポートパスを指定します。

myproject/admin.py
from django.contrib import admin


class MyAdminSite(admin.AdminSite): ...
myproject/apps.py
from django.contrib.admin.apps import AdminConfig


class MyAdminConfig(AdminConfig):
    default_site = "myproject.admin.MyAdminSite"
myproject/settings.py
INSTALLED_APPS = [
    # ...
    "myproject.apps.MyAdminConfig",  # replaces 'django.contrib.admin'
    # ...
]

同じ URLconf に複数の admin サイトを置く

同じ Django を使った Web サイトに、複数の admin サイトのインスタンスを作成できます。 AdminSite のインスタンスを複数作成し、それぞれを異なる URL に配置します。

このインスタンスでは、 /basic-admin//advanced-admin/ はそれぞれ AdminSite インスタンス myproject.admin.basic_sitemyproject.admin.advanced_site を使用した別々のバージョンの admin サイトです:

# urls.py
from django.urls import path
from myproject.admin import advanced_site, basic_site

urlpatterns = [
    path("basic-admin/", basic_site.urls),
    path("advanced-admin/", advanced_site.urls),
]

AdminSite インスタンスはコンストラクタに一つの引数、名前を渡します。この引数は 逆引き のためにURL名のプレフィックスとなります。これは複数の AdminSite を使用する場合にのみ必要です。

admin サイトにビューを追加する

ModelAdmin と同様に、 AdminSiteget_urls() メソッドを提供し、このメソッドをオーバーライドすることでサイトに追加のビューを定義できます。admin サイトに新しいビューを追加するには、ベースとなる get_urls() メソッドを拡張して、新しいビューのパターンを追加します。

注釈

admin テンプレートを使用する、またはベースとなる admin テンプレートを拡張するビューは、テンプレートをレンダリングする前に request.current_app を設定する必要があります。ビューが AdminSite にある場合は self.name を、ビューが ModelAdmin にある場合は self.admin_site.name を設定します。

パスワードリセット機能を追加する

URLconfに数行を追加することで、admin サイトにパスワードリセット機能を追加できます。具体的には、以下の4つのパターンを追加します:

from django.contrib import admin
from django.contrib.auth import views as auth_views

path(
    "admin/password_reset/",
    auth_views.PasswordResetView.as_view(
        extra_context={"site_header": admin.site.site_header}
    ),
    name="admin_password_reset",
),
path(
    "admin/password_reset/done/",
    auth_views.PasswordResetDoneView.as_view(
        extra_context={"site_header": admin.site.site_header}
    ),
    name="password_reset_done",
),
path(
    "reset/<uidb64>/<token>/",
    auth_views.PasswordResetConfirmView.as_view(
        extra_context={"site_header": admin.site.site_header}
    ),
    name="password_reset_confirm",
),
path(
    "reset/done/",
    auth_views.PasswordResetCompleteView.as_view(
        extra_context={"site_header": admin.site.site_header}
    ),
    name="password_reset_complete",
),

(上記は admin/ に admin を追加していることを前提としており、admin アプリ自体を含む行の前に ^admin/ で始まるURLを配置することが必要です)

admin_password_reset という名前のURLがあると、デフォルトの admin ログインページのパスワードボックスの下に "forgot your password? "というリンクが表示されます。

LogEntry オブジェクト

class models.LogEntry

LogEntry クラスは管理画面を通して行われたオブジェクトの追加、変更、削除を記録します。

LogEntry の属性

LogEntry.action_time

アクションの日時。

LogEntry.user

アクションを実行したユーザー( AUTH_USER_MODEL インスタンス)。

LogEntry.content_type

変更されたオブジェクトの ContentType

LogEntry.object_id

変更されたオブジェクトの主キーのテキスト表現。

LogEntry.object_repr

変更後のオブジェクトの repr()

LogEntry.action_flag

ログに記録されたアクションの種類: ADDITION, CHANGE, DELETION

たとえば、admin を通して行われたすべての追加操作のリストを取得する場合:

from django.contrib.admin.models import ADDITION, LogEntry

LogEntry.objects.filter(action_flag=ADDITION)
LogEntry.change_message

変更の詳細。たとえば編集の場合、メッセージには編集されたフィールドのリストが含まれます。Django の admin サイトでは、この内容を JSON 構造として整形し、get_change_message() が現在のユーザ言語で翻訳されたメッセージを再構成できるようにしています。カスタムコードではこれをプレーンな文字列として設定するかもしれません。この値を取得するには、直接アクセスするのではなく get_change_message() メソッドを使用することをお勧めします。

LogEntry メソッド

LogEntry.get_edited_object()

参照されているオブジェクトを返すショートカット。

LogEntry.get_change_message()

change_message を現在のユーザ言語に変換します。Django 1.10 より前に作成されたメッセージは、常にログに記録された言語で表示されます。

admin の URL を逆引きする

AdminSite がデプロイされると、そのサイトが提供するビューは Django の URL 逆引きシステム を使ってアクセスできるようになります。

AdminSite は以下のURLパターンを提供します:

ページ URL 名 パラメータ
インデックス index  
ログイン login  
ログアウト logout  
パスワードの変更 password_change  
パスワード変更完了 password_change_done  
国際化 JavaScript jsi18n  
アプリケーションのインデックスページ app_list app_label
オブジェクトのページへのリダイレクト view_on_site content_type_id, object_id

それぞれの ModelAdmin インスタンスは追加の名前付き URL のセットを提供します:

ページ URL 名 パラメータ
チェンジリスト {{ app_label }}_{{ model_name }}_changelist  
追加 {{ app_label }}_{{ model_name }}_add  
履歴 {{ app_label }}_{{ model_name }}_history object_id
削除 {{ app_label }}_{{ model_name }}_delete object_id
変更 {{ app_label }}_{{ model_name }}_change object_id

UserAdmin は以下の名前付きURLを提供します:

ページ URL 名 パラメータ
パスワードの変更 auth_user_password_change user_id

これらの名前付きURLはアプリケーション名前空間 admin とサイトインスタンス名に対応するインスタンス名前空間に登録されます。

つまり、デフォルトの admin 画面で特定の Choice オブジェクト(投票アプリケーションから)の変更ビューへの参照を取得したい場合、次のように呼び出します:

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

これは、最初に登録された管理アプリケーションのインスタンスを(インスタンス名が何であっても)見つけ、そのインスタンスで poll.Choice インスタンスを変更するためのビューを解決します。

特定の管理インスタンスのURLを見つけたい場合は、そのインスタンス名を current_app ヒントとして逆引きのコールに与えます。たとえば、特に custom という名前の管理インスタンスから管理ビューを取得したい場合は、以下のように呼び出す必要があります。

>>> change_url = reverse("admin:polls_choice_change", args=(c.id,), current_app="custom")

詳細は 名前空間のURLの逆引き のドキュメントを参照してください。

Django は、テンプレート内で admin の URL を簡単に逆引きできるように、アクション を引数に取る admin_urlname フィルタを提供しています:

{% load admin_urls %}
<a href="{% url opts|admin_urlname:'add' %}">Add user</a>
<a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a>

上記の例のアクションは上記の ModelAdmin インスタンスの URL 名の最後の部分と一致します。変数 opts には app_labelmodel_name 属性を持つ任意のオブジェクトを指定することができ、通常は現在のモデルの管理ビューから提供されます。

display デコレータ

display(*, boolean=None, ordering=None, description=None, empty_value=None)

このデコレータは list_displayreadonly_fields で使用できるカスタム表示関数に特定の属性を指定するために使用できます:

@admin.display(
    boolean=True,
    ordering="-publish_date",
    description="Is Published?",
)
def is_published(self, obj):
    return obj.publish_date is not None

これは、いくつかの属性を(元の長い名前で)関数に直接設定することと等価です。

def is_published(self, obj):
    return obj.publish_date is not None


is_published.boolean = True
is_published.admin_order_field = "-publish_date"
is_published.short_description = "Is Published?"

また、empty_value デコレータパラメータは、関数に直接割り当てられた empty_value_display 属性にマッピングされることに注意してください。真偽値 boolean と併用することはできません。

このデコレータの使用は、表示関数を作成する上で必須ではありませんが、 関数の目的を特定するための目印として、引数なしで使用すると便利です:

@admin.display
def published_year(self, obj):
    return obj.publish_date.year

この場合、関数に属性は追加されません。

staff_member_required デコレータ

staff_member_required(redirect_field_name='next', login_url='admin:login')

このデコレータは、認可が必要な admin ビューで使用されます。この関数でデコレーションされたビューは、以下の動作をするようになります。

  • ユーザーがログインしており、スタッフであり(User.is_staff=True)、アクティブであれば(User.is_active=True)、ビューを正常に実行します。
  • そうでない場合、リクエストは login_url パラメータで指定された URL にリダイレクトされ、 redirect_field_name で指定されたクエリ文字列変数に元々リクエストされていたパスが格納されます。例: /admin/login/?next=/admin/polls/question/3/

使用例:

from django.contrib.admin.views.decorators import staff_member_required


@staff_member_required
def my_view(request): ...
Back to Top