---
title: "Django の admin サイト"
version: 5.2
locale: ja
source: https://docs.djangoproject.com/ja/5.2/ref/contrib/admin/
canonical: https://djangodocs.dev/ja/5.2/ref/contrib/admin/
---
# Django の admin サイト

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

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

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

## 概要

admin サイトは [`startproject`](/ja/5.2/ref/django-admin/#django-admin-startproject) で使用されるデフォルトのプロジェクトテンプレートで有効になります。

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

1. `'django.contrib.admin'` とその依存関係である [`django.contrib.auth`](/ja/5.2/topics/auth/#module-django.contrib.auth), [`django.contrib.contenttypes`](/ja/5.2/ref/contrib/contenttypes/#module-django.contrib.contenttypes), [`django.contrib.messages`](/ja/5.2/ref/contrib/messages/#module-django.contrib.messages), および [`django.contrib.sessions`](/ja/5.2/topics/http/sessions/#module-django.contrib.sessions) を、 [`INSTALLED_APPS`](/ja/5.2/ref/settings/#std-setting-INSTALLED_APPS) 設定に追加してください。
2. [`DjangoTemplates`](/ja/5.2/topics/templates/#django.template.backends.django.DjangoTemplates) バックエンドを、[`TEMPLATES`](/ja/5.2/ref/settings/#std-setting-TEMPLATES) 設定で構成し、`django.template.context_processors.request`, `django.contrib.auth.context_processors.auth`, および `django.contrib.messages.context_processors.messages` を [`OPTIONS`](/ja/5.2/ref/settings/#std-setting-TEMPLATES-OPTIONS) の `'context_processors'` オプションに含めてください。
3. [`MIDDLEWARE`](/ja/5.2/ref/settings/#std-setting-MIDDLEWARE) 設定をカスタマイズしている場合、[`django.contrib.sessions.middleware.SessionMiddleware`](/ja/5.2/ref/middleware/#django.contrib.sessions.middleware.SessionMiddleware)、[`django.contrib.auth.middleware.AuthenticationMiddleware`](/ja/5.2/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware)、および [`django.contrib.messages.middleware.MessageMiddleware`](/ja/5.2/ref/middleware/#django.contrib.messages.middleware.MessageMiddleware) を含める必要があります。
4. [管理サイトのURLをあなたのURLconfにフックする](#hooking-adminsite-to-urlconf) 。

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

ログイン用のユーザーを作成する必要がある場合は、[`createsuperuser`](/ja/5.2/ref/django-admin/#django-admin-createsuperuser) コマンドを使用してください。デフォルトでは、管理サイトにログインするにはユーザーの [`is_staff`](/ja/5.2/ref/contrib/auth/#django.contrib.auth.models.User.is_staff) 属性が `True` に設定されている必要があります。

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

### 他のトピック

- [管理アクション](/ja/5.2/ref/contrib/admin/actions/)
- [`ModelAdmin` リストフィルタ](/ja/5.2/ref/contrib/admin/filters/)
- [Django admin ドキュメントジェネレータ](/ja/5.2/ref/contrib/admin/admindocs/)
- [admin アプリケーションの JavaScript カスタマイズ](/ja/5.2/ref/contrib/admin/javascript/)

> **See also**
>
> 本番環境での admin と関連する静的ファイル (画像、JavaScript、CSS) の配信について知りたい場合は、[ファイルを配信する](/ja/5.2/howto/deployment/wsgi/modwsgi/#serving-files) を参照してください。
>
> 問題が解決しない場合は、[FAQ: 管理インタフェース](/ja/5.2/faq/admin/) を参照してみてください。

## `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`](#django.contrib.admin.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`](/ja/5.2/ref/settings/#std-setting-INSTALLED_APPS) 設定内に `'django.contrib.admin'` を記述すると、Django は自動的に各アプリケーション内で `admin` モジュールを探してインポートします。

#### `class apps.AdminConfig`

これは、admin に対するデフォルトの [`AppConfig`](/ja/5.2/ref/applications/#django.apps.AppConfig) クラスです。Django が開始すると [`autodiscover()`](#django.contrib.admin.autodiscover) を呼び出します。

#### `class apps.SimpleAdminConfig`

このクラスは [`AdminConfig`](#django.contrib.admin.apps.AdminConfig) と同じように動作しますが、[`autodiscover()`](#django.contrib.admin.autodiscover) を呼び出しません。

#### `default_site`

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

#### `autodiscover()`

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

通常、この機能を手動で呼び出す必要はありません。Django が開始するとき [`AdminConfig`](#django.contrib.admin.apps.AdminConfig) が呼び出してくれます。

カスタム `AdminSite` を使用している場合、通常はすべての `ModelAdmin` サブクラスをコードにインポートし、それらをカスタム `AdminSite` に登録します。その場合、自動検出を無効にするには、[`INSTALLED_APPS`](/ja/5.2/ref/settings/#std-setting-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`

チェンジリストページで有効化するアクションのリストです。詳細は [管理アクション](/ja/5.2/ref/contrib/admin/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` をモデル内の `DateField` か `DateTimeField` の名前にセットすると、チェンジリストのページがそのフィールドによる日付ベースのドリルダウンナビゲーションを含むようになります。

実装例:

```
date_hierarchy = "pub_date"
```

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

```
date_hierarchy = "author__pub_date"
```

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

> **Note**
>
> `date_hierarchy` は内部的に [`QuerySet.datetimes()`](/ja/5.2/ref/models/querysets/#django.db.models.query.QuerySet.datetimes) を使用します。タイムゾーンサポートが有効 ([`USE_TZ = True`](/ja/5.2/ref/settings/#std-setting-USE_TZ)) な際に注意すべき点について、ドキュメントを参照してください。

#### `ModelAdmin.empty_value_display`

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

```
from django.contrib import admin

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

[`AdminSite.empty_value_display`](#django.contrib.admin.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` モデルに対するフォームが `name` と `title` の 2 つのフィールドのみを含むようにしたい場合、以下のように `fields` か `exclude` を指定することになります:

```
from django.contrib import admin

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

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

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

#### `ModelAdmin.fields`

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

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

上記の例では、指定したフィールド (`url`、`title`、`content`) だけが (結果として) フォーム上で表示されます。`fields` は [`ModelAdmin.readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields) で定義される値を持つことができ、読み取り専用で表示されます。

より複雑なレイアウトを作るには、[`fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets) オプションを参照してください。

`fields` オプションは、[`list_display`](#django.contrib.admin.ModelAdmin.list_display) と同じタイプの値を受け付けますが、呼び出し可能オブジェクトや関連フィールドの `__` ルックアップは受け付けません。モデルおよびモデル管理クラスのメソッド名は、[`readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields) にリストされている場合にのみ使用されます。

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

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

> **ModelAdmin.fieldsets オプションとの混同の可能性**
>
> この `fields` オプションと、次のセクションで説明する [`fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets) における `fields` ディクショナリキーは別物です。

`fields` オプションも [`fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets) オプションも指定されない場合、 Django はデフォルトで次のように表示します。 `AutoField` ではなく、かつ `editable=True` が設定されている各フィールドを、モデル内で定義された順序で単一のフィールドセットに表示します。その後に [`readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields) で定義されたフィールドを表示します。

#### `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`](/ja/5.2/ref/contrib/flatpages/#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 ページは以下のような見た目となります:

![](ref/contrib/admin/_images/fieldsets.png)

`fieldsets` と [`fields`](#django.contrib.admin.ModelAdmin.fields) オプションのどちらも存在しない場合、Django はデフォルトで `AutoField` と `editable=True` 以外の各フィールドを、単一のフィールドセットで、モデル内でフィールドが定義されたとおりの順番で表示します。

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

- **`fields`**

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

    実装例:

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

    [`fields`](#django.contrib.admin.ModelAdmin.fields) オプションと同様に、複数のフィールドを 1 行に表示するにはタプルでこれらのフィールドを囲んでください。この例では、`first_name` と `last_name` フィールドが 1 つの行に表示されます。

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

    `fields` は [`ModelAdmin.readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields) で定義される値を持つことができ、読み取り専用で表示されます。

    `fields` に呼び出し可能オブジェクトの名前を追加した場合、[`fields`](#django.contrib.admin.ModelAdmin.fields) オプションと同じルールが適用されます: 呼び出し可能オブジェクトは [`readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields) 内でリスト化される必要があります。
- **`classes`**

    フィールドセットに適用する追加のCSSクラスを含むリストまたはタプルです。これには、プロジェクト内で定義されたカスタムCSSクラスや、Djangoが提供するCSSクラスを含めることができます。デフォルトの管理サイトのCSSスタイルシート内では、特に役立つ2つのクラス、`collapse` と `wide` が定義されています。

    実装例:

    ```
    {
        "classes": ["wide", "collapse"],
    }
    ```

    `wide` スタイルが適用されたフィールドセットは、管理インターフェースで追加の横幅が与えられます。`collapse` スタイルが適用された名前付きフィールドセットは、初期状態で折りたたまれ、表示/非表示を切り替えるための展開可能なウィジェットが使用されます。

    > **Changed in Django 5.1**
    >
    > `collapse` クラスを使用する `fieldsets` は、`name` が定義されている場合、`<details>` および `<summary>` 要素を使用するようになりました。
- **`description`**

    各フィールドセットの見出しの下に表示されるオプションの追加テキストの文字列です。

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

> **TabularInline は fieldsets の機能の一部しか利用できません**
>
> [`TabularInline`](#django.contrib.admin.TabularInline) で `fieldsets` を使用する際は、機能が制限されています。`TabularInline` レイアウト内で表示するフィールドとその順序を指定するには、`field_options` 辞書内で `fields` を定義する必要があります。
>
> その他のすべての機能はサポートされていません。これには、フィールドのグループにタイトルを定義するための `name` の使用が含まれます。

#### `ModelAdmin.filter_horizontal`

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

#### `ModelAdmin.filter_vertical`

[`filter_horizontal`](#django.contrib.admin.ModelAdmin.filter_horizontal) と同じですが、フィルタインターフェイスを垂直方向に表示し、非選択のオプションは選択済みのオプションの上部に表示されます。

#### `ModelAdmin.form`

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

例については [カスタムのバリデーションを admin に追加する](#admin-custom-validation) を参照してください。

> **Meta.model 属性を省略する**
>
> [`ModelForm`](/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm) で `Meta.model` 属性を定義した場合、`Meta.fields` 属性 (もしくは `Meta.exclude` 属性) も定義する必要があります。しかし、admin 自身がフィールドを定義する方法を持っているため、`Meta.fields` 属性は無視されます。
>
> `ModelForm` を admin のみで使用する場合は、`ModelAdmin` が使用する正しいモデルを提供するため、`Meta.model` 属性を省略するのが手っ取り早い解決法です。あるいは、`Meta` クラス内で `fields = []` をセットして `ModelForm` のバリデーションの条件を満たすこともできます。

> **ModelAdmin.exclude が優先されます**
>
> `ModelForm` と `ModelAdmin` の両方で `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`](/ja/5.2/ref/forms/fields/#django.forms.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](/ja/5.2/ref/forms/api/) を参照してください。

> **Warning**
>
> リレーションフィールド (例えば [`ForeignKey`](/ja/5.2/ref/models/fields/#django.db.models.ForeignKey) や [`ManyToManyField`](/ja/5.2/ref/models/fields/#django.db.models.ManyToManyField)) でカスタムウィジェットを使用したいときは、,  `raw_id_fields`、`radio_fields`、`autocomplete_fields` にそのフィールドの名前を含まないようにしてください。
>
> `formfield_overrides` は、`raw_id_fields`、`radio_fields`、`autocomplete_fields` のどれかがセットされたリレーションフィールドのウィジェットは変更しません。これは、`raw_id_fields`、`radio_fields`、`autocomplete_fields` の 3 つがこれら自身のカスタムウィジェットを暗示するからです。

#### `ModelAdmin.inlines`

後述の [`InlineModelAdmin`](#django.contrib.admin.InlineModelAdmin) オブジェクトと [`ModelAdmin.get_formsets_with_inlines()`](#django.contrib.admin.ModelAdmin.get_formsets_with_inlines) を参照してください。

#### `ModelAdmin.list_display`

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

実装例:

```
list_display = ["first_name", "last_name"]
```

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

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

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

  ```
  class PersonAdmin(admin.ModelAdmin):
      list_display = ["first_name", "last_name"]
  ```
- リレーション先フィールドの名前を `__` 表記で記述します。例えば、次のようにします。

  ```
  class PersonAdmin(admin.ModelAdmin):
      list_display = ["city__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"]
  ```

> **Changed in Django 5.1**
>
> 関連フィールドを対象にする際に `__` ルックアップを使用するサポートが追加されました。

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

- フィールドが `ForeignKey` の場合、 Django はリレーション先オブジェクトの `__str__()` を表示します。
- `ManyToManyField` フィールドは、テーブル内で各行に対して個別の SQL ステートメントを実行する可能性があるため、サポートされていません。それでも使いたい場合は、モデルにカスタムメソッドを作成し、そのメソッドの名前を `list_display` に追加してください。 (`list_display` 内でのカスタムメソッドについてより詳しくは下記を参照してください。)
- フィールドが `BooleanField` の場合、Django は `True`, `False`, `None` の代わりに、かわいい "yes", "no", "unknown" アイコンを表示します。
- 与えられた文字列がモデル、`ModelAdmin`、呼び出し可能オブジェクトのどれかの場合、Django はデフォルトで HTML エスケープして出力します。ユーザーの入力をエスケープしたり非エスケープのタグを使う場合、[`format_html()`](/ja/5.2/ref/utils/#django.utils.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()`](#django.contrib.admin.display) デコレータで呼び出し可能オブジェクトをラップし、 `description` 引数を渡すことで、カラムのタイトルをカスタマイズできます。
- フィールドの値が `None`、空の文字列、エレメントを持たない iterable のいずれかの場合、Django は `-` (ダッシュ) を表示します。この挙動は [`AdminSite.empty_value_display`](#django.contrib.admin.AdminSite.empty_value_display) でオーバーライドできます。

  ```
  from django.contrib import admin

  admin.site.empty_value_display = "(None)"
  ```

  [`ModelAdmin.empty_value_display`](#django.contrib.admin.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()`](#django.contrib.admin.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()`](#django.contrib.admin.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
  ```

  [クエリ式](/ja/5.2/ref/models/expressions/) は `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()`](#django.contrib.admin.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)
  ```
- `list_display` のフィールド名はHTMLの出力でも `<th>` 要素に `column-<field_name>` という形でCSSクラスとして表示されます。これは例えばCSSファイルでカラムの幅を設定するのに使うことができます。
- Django は、`list_display` の各要素を以下の順番で解釈しようとします。

  - モデルのフィールド、またはリレーション先のフィールド由来のフィールド。
  - 呼び出し可能オブジェクト。
  - `ModelAdmin` 属性を表す文字列。
  - モデル属性を表す文字列。

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

#### `ModelAdmin.list_display_links`

[`list_display`](#django.contrib.admin.ModelAdmin.list_display) 内のフィールドにおいて "変更" ページへのリンクをコントロールするには、`list_display_links` を使用してください。

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

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

  1 つないし複数のフィールドを指定できます。`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"]
```

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

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

#### `ModelAdmin.list_editable`

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

> **Note**
>
> `list_editable` は、他のオプションと特定部分で相互関係にあります。以下のルールに注意してください。
>
> - `list_editable` 内のすべてのフィールドは `list_display` に含まれている必要があります。表示されていないフィールドは編集できないのです！
> - `list_editable` と `list_display_links` に同じフィールドを同時に指定することはできません -- 1 つのフィールドがフォームとリンクの両方になることはできないからです。
>
> これらのルールを破った場合、バリデーションエラーとなります。

#### `ModelAdmin.list_filter`

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

最もシンプルな `list_filter` はフィルタリングを有効にするフィールド名のリストまたはタプルを受け取りますが、より高度なオプションもいくつか用意されています。詳細は [ModelAdmin リストフィルタ](/ja/5.2/ref/contrib/admin/filters/#modeladmin-list-filters) を参照してください。

#### `ModelAdmin.list_max_show_all`

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

#### `ModelAdmin.list_per_page`

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

#### `ModelAdmin.list_select_related`

admin のチェンジリストページでオブジェクトのリストを検索するときに [`select_related()`](/ja/5.2/ref/models/querysets/#django.db.models.query.QuerySet.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()`](#django.contrib.admin.ModelAdmin.get_list_select_related) メソッドを実装できます。

> **Note**
>
> `ModelAdmin` は [`select_related()`](/ja/5.2/ref/models/querysets/#django.db.models.query.QuerySet.select_related) がチェンジリストの `QuerySet` で既に呼び出されていた場合、この属性を無視します。

#### `ModelAdmin.ordering`

Django の admin ビューでオブジェクトのリストをどのようにソートするかを指定するには、 `ordering` をセットしてください。モデルの [`ordering`](/ja/5.2/ref/models/options/#django.db.models.Options.ordering) パラメータと同じフォーマットでリストかタプルを与えてください。

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

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

> **並べ替えやソートに伴うパフォーマンス上の注意**
>
> 全体のソートのための単一もしくは unique together フィールド指定をチェンジリストが見つけられない場合、チェンジリストは `pk` をチェンジリストに追加します。これは結果の決定論的なソートを保証するためです。
>
> たとえば、デフォルトのソートが一意でない `name` フィールドによって実行される場合、チェンジリストは `name` と `pk` でソートされます。テーブルのレコード数が多く、 `name` と `pk` のインデックスがない場合は、パフォーマンスの低下を招きます。

#### `ModelAdmin.paginator`

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

#### `ModelAdmin.prepopulated_fields`

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

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

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

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

`prepopulated_fields` は `DateTimeField`、`ForeignKey`、`OneToOneField`、`ManyToManyField` フィールドを受け入れません。

#### `ModelAdmin.preserve_filters`

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

#### `ModelAdmin.show_facets`

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

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

#### `class ShowFacets`

[`ModelAdmin.show_facets`](#django.contrib.admin.ModelAdmin.show_facets) に指定できる値の Enum。

#### `ALWAYS`

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

#### `ALLOW`

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

#### `NEVER`

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

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

```
from django.contrib import admin

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

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

#### `ModelAdmin.radio_fields`

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

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

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

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

#### `ModelAdmin.autocomplete_fields`

`autocomplete_fields` は、[Select2](https://select2.org/) オートコンプリート入力に変更したい `ForeignKey` ないし `ManyToManyField` フィールドのリストです。

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

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

オートコンプリート検索はリレーション先オブジェクトの `ModelAdmin` を使用するため、`ModelAdmin` に [`search_fields`](#django.contrib.admin.ModelAdmin.search_fields) を定義する必要があります。

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

結果のソートおよびページ分割は、関係する `ModelAdmin` の [`get_ordering()`](#django.contrib.admin.ModelAdmin.get_ordering) と [`get_paginator()`](#django.contrib.admin.ModelAdmin.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`](#django.contrib.admin.ModelAdmin.ordering) を使った並べ替えは、巨大なクエリセットは遅くなるため、パフォーマンスの問題の原因となります。
>
> また、検索フィールドがデータベースによるインデックス化がされていないフィールドを含む場合、巨大なテーブルでは貧弱なパフォーマンスしか発揮できなくなってしまいます。
>
> このような場合は、フルテキストのインデックスサーチを使用した独自の [`ModelAdmin.get_search_results()`](#django.contrib.admin.ModelAdmin.get_search_results) 実装を記述するのがよいでしょう。
>
> また、デフォルトの paginator は常に  `count()` を発行するため、巨大なテーブルでは `Paginator` を変更するのがお勧めです。例えば、`Paginator.count` プロパティのデフォルトの実装をオーバーライドできます。

#### `ModelAdmin.raw_id_fields`

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

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

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

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

![](ref/contrib/admin/_images/raw_id_fields.png)

#### `ModelAdmin.readonly_fields`

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

[`ModelAdmin.fields`](#django.contrib.admin.ModelAdmin.fields) や [`ModelAdmin.fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets) で明示的に並び順を定義しないで `readonly_fields` を使った場合、これらのフィールドはすべての編集可能なフィールドの後に表示されます。

read-only のフィールドはモデルのフィールドからデータを表示するだけではなく、モデルや `ModelAdmin` クラス自身のメソッドの出力を表示させることもできます。これは [`ModelAdmin.list_display`](#django.contrib.admin.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_as` が `True` の場合、"保存して 1 つ追加" が "新規に保存" ボタンに変更され、既存のオブジェクトを変更するのではなく (新しい ID) で新規のオブジェクトが作成されるようになります。

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

#### `ModelAdmin.save_as_continue`

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

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

#### `ModelAdmin.save_on_top`

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

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

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

#### `ModelAdmin.search_fields`

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

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

```
search_fields = ["foreign_key__related_fieldname"]
```

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

```
search_fields = ["user__email"]
```

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

```sql
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` 句と等価な処理を行います。

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

もし `icontains` ルックアップを使用したくない場合は、フィールドに追加することで任意のルックアップを使用できます。例えば、`search_fields` を `['first_name__exact']` に設定することで、[`exact`](/ja/5.2/ref/models/querysets/#std-fieldlookup-exact) を使用できます。

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

| プレフィックス | ルックアップ |
| --- | --- |
| ^ | [`istartswith`](/ja/5.2/ref/models/querysets/#std-fieldlookup-istartswith) |
| = | [`iexact`](/ja/5.2/ref/models/querysets/#std-fieldlookup-iexact) |
| @ | [`search`](/ja/5.2/ref/contrib/postgres/search/#std-fieldlookup-search) |
| None | [`icontains`](/ja/5.2/ref/models/querysets/#std-fieldlookup-icontains) |

検索方法をカスタムする必要がある場合は、[`ModelAdmin.get_search_results()`](#django.contrib.admin.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`](#django.contrib.admin.ModelAdmin.list_display) で指定された全てのモデルフィールド (および [`display()`](#django.contrib.admin.display) デコレータの `ordering` 引数を使用する呼び出し可能オブジェクト、または `admin_order_field` 属性を持つ呼び出し可能オブジェクト) によるソートが可能です。

特定のカラムでのソートを無効化したい場合、 `sortable_by` に [`list_display`](#django.contrib.admin.ModelAdmin.list_display) サブセットのコレクション (例: `list` 、 `tuple` 、 `set`) をセットしてください。空のコレクションを指定すると、すべてのカラムでソート不可となります。

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

#### `ModelAdmin.view_on_site`

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

値は、真偽値か呼び出し可能オブジェクトで指定します。`True` (デフォルトです) の場合、オブジェクトの [`get_absolute_url()`](/ja/5.2/ref/models/instances/#django.db.models.Model.get_absolute_url) メソッドが使われ、URLが生成されます。

モデルが [`get_absolute_url()`](/ja/5.2/ref/models/instances/#django.db.models.Model.get_absolute_url) メソッドを持っていても "サイトで見る" ボタンを表示したくない場合は、`view_on_site` に `False` をセットしてください:

```
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-overriding-templates) セクションでは、デフォルトの admin テンプレートをオーバーライドないし拡張する方法を説明しています。[`ModelAdmin`](#django.contrib.admin.ModelAdmin) ビューで使用されるデフォルトのテンプレートをオーバーライドするには、以下のオプションを使用してください:

#### `ModelAdmin.add_form_template`

カスタムンテンプレートの絶対パスで、[`add_view()`](#django.contrib.admin.ModelAdmin.add_view) で使われます。

#### `ModelAdmin.change_form_template`

カスタムンテンプレートの絶対パスで、[`change_view()`](#django.contrib.admin.ModelAdmin.change_view) で使われます。

#### `ModelAdmin.change_list_template`

カスタムンテンプレートの絶対パスで、[`changelist_view()`](#django.contrib.admin.ModelAdmin.changelist_view) で使われます。

#### `ModelAdmin.delete_confirmation_template`

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

#### `ModelAdmin.delete_selected_confirmation_template`

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

#### `ModelAdmin.object_history_template`

カスタムンテンプレートの絶対パスで、[`history_view()`](#django.contrib.admin.ModelAdmin.history_view) で使われます。

#### `ModelAdmin.popup_response_template`

カスタムンテンプレートの絶対パスで、[`response_add()`](#django.contrib.admin.ModelAdmin.response_add)、[`response_change()`](#django.contrib.admin.ModelAdmin.response_change)、[`response_delete()`](#django.contrib.admin.ModelAdmin.response_delete) の 3 つで使われます。

### `ModelAdmin` のメソッド

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

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

`save_model` メソッドには、`HttpRequest`、モデルのインスタンス、`ModelForm` のインスタンス、追加か変更かを表す真偽値が渡されます。このメソッドをオーバーライドすると、保存の前後に操作を追加できます。`super().save_model()` を呼び出して、[`Model.save()`](/ja/5.2/ref/models/instances/#django.db.models.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()`](/ja/5.2/ref/models/instances/#django.db.models.Model.delete) を使ってオブジェクトを削除してください。

#### `ModelAdmin.delete_queryset(request, queryset)`

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

#### `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()
```

関連項目: [フォームセット内のオブジェクトを保存する](/ja/5.2/topics/forms/modelforms/#saving-objects-in-the-formset)

> **Warning**
>
> `ModelAdmin` プロパティを返すすべてのフックは、その値のコピーではなく、プロパティ自体を返します。動的に値を変更すると、予期しない結果を招くことがあります。
>
> [`ModelAdmin.get_readonly_fields()`](#django.contrib.admin.ModelAdmin.get_readonly_fields) を例に取ってみましょう。
>
> ```
> class PersonAdmin(admin.ModelAdmin):
>     readonly_fields = ["name"]
>
>     def get_readonly_fields(self, request, obj=None):
>         readonly = super().get_readonly_fields(request, obj)
>         if not request.user.is_superuser:
>             readonly.append("age")  # Edits the class attribute.
>         return readonly
> ```
>
> これにより、`readonly_fields` は `["name", "age", "age", ...]` となり、スーパーユーザーであっても、非スーパーユーザーがページを訪れるたびに `"age"` が追加されることになります。

#### `ModelAdmin.get_ordering(request)`

`get_ordering` メソッドは引数に `request` を取り、[`ordering`](#django.contrib.admin.ModelAdmin.ordering) のときと同じような `list` か `tuple` を返すことが期待されます。次に例を示します。

```
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`](#django.contrib.admin.ModelAdmin.search_fields) に含まれるフィールドを検索します。

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

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

```
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')` となります。

#### `ModelAdmin.save_related(request, form, formsets, change)`

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

#### `ModelAdmin.get_autocomplete_fields(request)`

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

#### `ModelAdmin.get_readonly_fields(request, obj=None)`

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

#### `ModelAdmin.get_prepopulated_fields(request, obj=None)`

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

#### `ModelAdmin.get_list_display(request)`

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

#### `ModelAdmin.get_list_display_links(request, list_display)`

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

#### `ModelAdmin.get_exclude(request, obj=None)`

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

#### `ModelAdmin.get_fields(request, obj=None)`

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

#### `ModelAdmin.get_fieldsets(request, obj=None)`

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

#### `ModelAdmin.get_list_filter(request)`

`get_list_filter` メソッドには、`HttpRequest` が渡され、[`list_filter`](#django.contrib.admin.ModelAdmin.list_filter) 属性のときと同じ種類のシーケンス型を返すことが期待されます。

#### `ModelAdmin.get_list_select_related(request)`

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

#### `ModelAdmin.get_search_fields(request)`

`get_search_fields` メソッドには、`HttpRequest` が渡され、[`search_fields`](#django.contrib.admin.ModelAdmin.search_fields) 属性のときと同じ種類のシーケンス型を返すことが期待されます。

#### `ModelAdmin.get_sortable_by(request)`

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

デフォルトの実装では、セットされている場合は [`sortable_by`](#django.contrib.admin.ModelAdmin.sortable_by) を返します。セットされていなければ [`get_list_display()`](#django.contrib.admin.ModelAdmin.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` メソッドは、編集中の `HttpRequest` と `obj` (追加フォームの場合は `None`) を受け取り、以下の [`InlineModelAdmin`](#django.contrib.admin.InlineModelAdmin) セクションで説明されているように、[`InlineModelAdmin`](#django.contrib.admin.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`](#django.contrib.admin.ModelAdmin.inlines) で定義したクラスのインスタンスにしてください。間違えると、リレーション先オブジェクトを追加する際に "Bad Request" が発生する可能性があります。

#### `ModelAdmin.get_inlines(request, obj)`

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

#### `ModelAdmin.get_urls()`

`ModelAdmin` の `get_urls` メソッドは URLconf と同じようにその ModelAdmin で使用する URL を返します。 そのため、 [URL ディスパッチャ](/ja/5.2/topics/http/urls/) で説明されているように、ビューの `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 してください:

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

> **Note**
>
> `self.my_view` 関数が `self.admin_site.admin_view` でラップされていることに注意してください。これは重要であり、次の2つのことを保証します:
>
> 1. パーミッションチェックが実行され、アクティブなスタッフユーザーだけがビューにアクセスできるようにします。
> 2. [`django.views.decorators.cache.never_cache()`](/ja/5.2/topics/http/decorators/#django.views.decorators.cache.never_cache) デコレータはキャッシュを防ぐために適用され、返される情報が最新であることを保証します。

> **Note**
>
> カスタムパターンが通常の管理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`](/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm) クラスを返します。[`add_view()`](#django.contrib.admin.ModelAdmin.add_view) と [`change_view()`](#django.contrib.admin.ModelAdmin.change_view) を参照してください。

基本の実装は [`modelform_factory()`](/ja/5.2/ref/forms/models/#django.forms.models.modelform_factory) を使用して [`form`](#django.contrib.admin.ModelAdmin.form) をサブクラス化し、[`fields`](#django.contrib.admin.ModelAdmin.fields) や [`exclude`](#django.contrib.admin.ModelAdmin.exclude) といった属性によって修正されます。なので、例えばスーパーユーザーに対して追加的なフィールドを与えたい場合は、以下のように基本のフォームを変更できます:

```
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`](/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm) クラスを直接返すこともできます。

#### `ModelAdmin.get_formsets_with_inlines(request, obj=None)`

admin の追加や変更のビューで使用するための (`FormSet`, [`InlineModelAdmin`](#django.contrib.admin.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)`

`ModelAdmin` の `formfield_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` に基づいたフィルタを行うことができます ([リレーションシップを扱うフィールド](/ja/5.2/ref/forms/fields/#fields-which-handle-relationships) を参照してください)。たとえば:

```
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_foreignkey` や `formfield_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`](/ja/5.2/ref/exceptions/#django.core.exceptions.ValidationError) とともに失敗します。

#### `ModelAdmin.get_changelist(request, **kwargs)`

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

#### `ModelAdmin.get_changelist_form(request, **kwargs)`

チェンジリストページの `Formset` で使うための [`ModelForm`](/ja/5.2/topics/forms/modelforms/#django.forms.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 属性を省略する**
>
> [`ModelForm`](/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm) で `Meta.model` 属性を定義した場合、`Meta.fields` 属性 (ないし `Meta.exclude` 属性) も定義する必要があります。しかし `ModelAdmin` はこの値を無視して、[`ModelAdmin.list_editable`](#django.contrib.admin.ModelAdmin.list_editable) 属性をオーバーライドします。最も簡単な解決方法は、`Meta.model` 属性を除外することです。これは `ModelAdmin` が使用する正しいモデルを提供するからです。

#### `ModelAdmin.get_changelist_formset(request, **kwargs)`

[`list_editable`](#django.contrib.admin.ModelAdmin.list_editable) を使っている場合、チェンジリストページで使用するための [ModelFormSet](/ja/5.2/topics/forms/modelforms/#model-formsets) クラスを返します。カスタムのフォームセットを使うには、たとえば、次のようにします。

```
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`](#django.contrib.admin.ModelAdmin.list_filter) はその仕組みで動作します。ルックアップは [`QuerySet.filter()`](/ja/5.2/ref/models/querysets/#django.db.models.query.QuerySet.filter) (例 `user__email=user@example.com`) で使われているものと似ています。クエリ文字列のルックアップはユーザによって操作される可能性があるため、無許可のデータ漏洩を防ぐためにサニタイズする必要があります。

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

デフォルトでは、 `lookup_allowed()` はモデルのローカルフィールド、 [`list_filter`](#django.contrib.admin.ModelAdmin.list_filter) で使用されるフィールドパス (ただし、 [`get_list_filter()`](#django.contrib.admin.ModelAdmin.get_list_filter) からのパスは使用できません)、 [`limit_choices_to`](/ja/5.2/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to) が [`raw_id_fields`](#django.contrib.admin.ModelAdmin.raw_id_fields) で正しく機能するために必要なルックアップへのアクセスを許可します。

[`ModelAdmin`](#django.contrib.admin.ModelAdmin) サブクラスで許可されるルックアップをカスタマイズするには、このメソッドをオーバーライドします。

#### `ModelAdmin.has_view_permission(request, obj=None)`

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

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

#### `ModelAdmin.has_add_permission(request)`

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

#### `ModelAdmin.has_change_permission(request, obj=None)`

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

#### `ModelAdmin.has_delete_permission(request, obj=None)`

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

#### `ModelAdmin.has_module_permission(request)`

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

#### `ModelAdmin.get_queryset(request)`

`ModelAdmin` の `get_queryset` メソッドは admin サイトで編集可能なモデルインスタンスのすべての [`QuerySet`](/ja/5.2/ref/models/querysets/#django.db.models.query.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`](/ja/5.2/ref/contrib/messages/#module-django.contrib.messages) バックエンドを使ってユーザーにメッセージを送ります。[カスタムの ModelAdmin の例](/ja/5.2/ref/contrib/admin/actions/#custom-admin-action) を参照してください。

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

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

このビューで使用する paginator のインスタンスを返します。デフォルトでは [`paginator`](#django.contrib.admin.ModelAdmin.paginator) のインスタンスを返します。

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

[`add_view()`](#django.contrib.admin.ModelAdmin.add_view) ステージに対する [`HttpResponse`](/ja/5.2/ref/request-response/#django.http.HttpResponse) を決定します。

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

#### `ModelAdmin.response_change(request, obj)`

[`change_view()`](#django.contrib.admin.ModelAdmin.change_view) ステージに対する [`HttpResponse`](/ja/5.2/ref/request-response/#django.http.HttpResponse) を決定します。

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

#### `ModelAdmin.response_delete(request, obj_display, obj_id)`

[`delete_view()`](#django.contrib.admin.ModelAdmin.delete_view) ステージに対する [`HttpResponse`](/ja/5.2/ref/request-response/#django.http.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_value` は `name` フィールドの初期値を `initial_value` にセットします。

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

```
def get_changeform_initial_data(self, request):
    return {"name": "custom_initial_value"}
```

#### `ModelAdmin.get_deleted_objects(objs, request)`

[`delete_view()`](#django.contrib.admin.ModelAdmin.delete_view) と "delete selected" [アクション](/ja/5.2/ref/contrib/admin/actions/) の削除処理をカスタマイズするフックです。

引数 `objs` は削除するオブジェクト (`QuerySet` またはモデルインスタンスのリスト) の同型イテラブルで、 `request` は [`HttpRequest`](/ja/5.2/ref/request-response/#django.http.HttpRequest) です。

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

`deleted_objects` は削除されるすべてのオブジェクトを表す文字列のリストです。削除されるオブジェクトにリレーション先オブジェクトがある場合、リストはネストされ、それらのリレーション先オブジェクトも含まれます。リストはテンプレート内で [`unordered_list`](/ja/5.2/ref/templates/builtins/#std-templatefilter-unordered_list) フィルタを使ってフォーマットされます。

`model_count` は各モデルの [`verbose_name_plural`](/ja/5.2/ref/models/options/#django.db.models.Options.verbose_name_plural) と削除されるオブジェクトの数をマッピングした辞書です。

`perms_need` は [`verbose_name`](/ja/5.2/ref/models/options/#django.db.models.Options.verbose_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`](/ja/5.2/ref/template-response/#django.template.response.TemplateResponse) インスタンスを返し、レンダリング前のレスポンスデータを簡単にカスタマイズできます。詳細は [TemplateResponse のドキュメント](/ja/5.2/ref/template-response/) を参照してください。

### `ModelAdmin` アセットの定義

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

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

[staticfiles アプリ](/ja/5.2/ref/contrib/staticfiles/) は、すべてのアセットのパスの前に [`STATIC_URL`](/ja/5.2/ref/settings/#std-setting-STATIC_URL) ([`STATIC_URL`](/ja/5.2/ref/settings/#std-setting-STATIC_URL) が `None` の場合は [`MEDIA_URL`](/ja/5.2/ref/settings/#std-setting-MEDIA_URL)) を付与します。 [フォーム上の通常のアセット定義](/ja/5.2/topics/forms/media/#form-asset-paths) と同じルールが適用されます。

#### jQuery

Django admin の JavaScript は [jQuery](https://jquery.com) ライブラリを使用します。

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

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

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

[`ModelAdmin`](#django.contrib.admin.ModelAdmin) と [`InlineModelAdmin`](#django.contrib.admin.InlineModelAdmin) には、フォームやフォームセットのJavaScriptファイルへのパスを格納する `Media` オブジェクトのリストを返す `media` プロパティがあります。 [`DEBUG`](/ja/5.2/ref/settings/#std-setting-DEBUG) が `True` の場合、 `jquery.js` を含む様々な JavaScript ファイルの圧縮されていないバージョンを返します。そうでない場合は、 "minify" されたバージョンを返します。

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

また、管理画面でデータのカスタムバリデーションを追加することもできます。自動管理インターフェイスは [`django.forms`](/ja/5.2/ref/forms/api/#module-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` を使用することは重要です。そうしないと問題が発生する可能性があります。 [カスタムバリデーション](/ja/5.2/ref/forms/validation/) に関する [フォーム](/ja/5.2/ref/forms/) のドキュメント、そしてより具体的には [モデルフォームのバリデーションに関する注意事項](/ja/5.2/topics/forms/modelforms/#overriding-modelform-clean-method) を参照してください。

## `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
from myapp.models import Author, Book

class BookInline(admin.TabularInline):
    model = Book

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

admin.site.register(Author, AuthorAdmin)
```

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

- [`TabularInline`](#django.contrib.admin.TabularInline)
- [`StackedInline`](#django.contrib.admin.StackedInline)

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

### `InlineModelAdmin` のオプション

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

- [`form`](#django.contrib.admin.InlineModelAdmin.form)
- [`fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets)
- [`fields`](#django.contrib.admin.ModelAdmin.fields)
- [`formfield_overrides`](#django.contrib.admin.ModelAdmin.formfield_overrides)
- [`exclude`](#django.contrib.admin.ModelAdmin.exclude)
- [`filter_horizontal`](#django.contrib.admin.ModelAdmin.filter_horizontal)
- [`filter_vertical`](#django.contrib.admin.ModelAdmin.filter_vertical)
- [`ordering`](#django.contrib.admin.ModelAdmin.ordering)
- [`prepopulated_fields`](#django.contrib.admin.ModelAdmin.prepopulated_fields)
- [`get_fieldsets()`](#django.contrib.admin.ModelAdmin.get_fieldsets)
- [`get_queryset()`](#django.contrib.admin.ModelAdmin.get_queryset)
- [`radio_fields`](#django.contrib.admin.ModelAdmin.radio_fields)
- [`readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_fields)
- [`raw_id_fields`](#django.contrib.admin.InlineModelAdmin.raw_id_fields)
- [`formfield_for_choice_field()`](#django.contrib.admin.ModelAdmin.formfield_for_choice_field)
- [`formfield_for_foreignkey()`](#django.contrib.admin.ModelAdmin.formfield_for_foreignkey)
- [`formfield_for_manytomany()`](#django.contrib.admin.ModelAdmin.formfield_for_manytomany)
- [`has_module_permission()`](#django.contrib.admin.ModelAdmin.has_module_permission)

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

#### `InlineModelAdmin.model`

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

#### `InlineModelAdmin.fk_name`

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

#### `InlineModelAdmin.formset`

これはデフォルトでは [`BaseInlineFormSet`](/ja/5.2/topics/forms/modelforms/#django.forms.models.BaseInlineFormSet) です。自分自身のフォームセットを使用すると、カスタマイズの幅が広がります。インラインは [モデル フォームセット](/ja/5.2/topics/forms/modelforms/#model-formsets) で構築されます。

#### `InlineModelAdmin.form`

`form` に対する値で、デフォルトは `ModelForm` です。これは、このインラインに対してフォームセットが生成される際に [`inlineformset_factory()`](/ja/5.2/ref/forms/models/#django.forms.models.inlineformset_factory) に渡されるものです。

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

#### `InlineModelAdmin.classes`

インラインでレンダリングされるフィールドセットに適用する追加のCSSクラスを含むリストまたはタプルです。デフォルトは `None` です。[`fieldsets`](#django.contrib.admin.ModelAdmin.fieldsets) で設定されたクラスと同様に、`collapse` クラスが付けられたインラインは、展開可能なウィジェットを使用して初期状態で折りたたまれます。

> **Changed in Django 5.1**
>
> `collapse` クラスを使用する `fieldsets` は、`name` が定義されている場合、`<details>` および `<summary>` 要素を使用するようになりました。

#### `InlineModelAdmin.extra`

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

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

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

[`InlineModelAdmin.get_extra()`](#django.contrib.admin.InlineModelAdmin.get_extra) でも追加フォームの数をカスタマイズできます。

#### `InlineModelAdmin.max_num`

インラインに表示するフォームの最大数をコントロールします。オブジェクトの数と直接関係はありませんが、値が小さい場合には関係する可能性があります。詳しくは [編集可能なオブジェクトの数を制限する](/ja/5.2/topics/forms/modelforms/#model-formsets-max-num) を参照してください。

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

#### `InlineModelAdmin.min_num`

インラインに表示するフォームの最小数をコントロールします。詳しくは [`modelformset_factory()`](/ja/5.2/ref/forms/models/#django.forms.models.modelformset_factory) を参照してください。

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

#### `InlineModelAdmin.raw_id_fields`

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

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

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

#### `InlineModelAdmin.template`

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

#### `InlineModelAdmin.verbose_name`

モデル内部の `Meta` クラスの [`verbose_name`](/ja/5.2/ref/models/options/#django.db.models.Options.verbose_name) のオーバーライドです。

#### `InlineModelAdmin.verbose_name_plural`

モデル内部の `Meta` クラスの [`verbose_name_plural`](/ja/5.2/ref/models/options/#django.db.models.Options.verbose_name_plural) をオーバーライドします。これが与えられず、 [`InlineModelAdmin.verbose_name`](#django.contrib.admin.InlineModelAdmin.verbose_name) が定義されている場合、 Django は [`InlineModelAdmin.verbose_name`](#django.contrib.admin.InlineModelAdmin.verbose_name) \+ `'s'` を使用します。

#### `InlineModelAdmin.can_delete`

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

#### `InlineModelAdmin.show_change_link`

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

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

admin の追加/変更ビューで使用する [`BaseInlineFormSet`](/ja/5.2/topics/forms/modelforms/#django.forms.models.BaseInlineFormSet) クラスを返します。 `obj` は編集対象の親オブジェクト、または新しい親オブジェクトを追加する場合は `None` です。 [`ModelAdmin.get_formsets_with_inlines`](#django.contrib.admin.ModelAdmin.get_formsets_with_inlines) の例を参照してください。

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

使用する追加インラインフォームの数を返します。デフォルトでは、[`InlineModelAdmin.extra`](#django.contrib.admin.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`](#django.contrib.admin.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`](#django.contrib.admin.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` は編集される親オブジェクトです。

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

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

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

```
from django.db import models

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

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, Person

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

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

admin.site.register(Person, PersonAdmin)
```

### 多対多のモデルを扱う

デフォルトでは、多対多のリレーションに対する管理ウィジェットは、実際に [`ManyToManyField`](/ja/5.2/ref/models/fields/#django.db.models.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
from myapp.models import Group

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

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

admin.site.register(Group, GroupAdmin)
```

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

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

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

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

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

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

[`ManyToManyField`](/ja/5.2/ref/models/fields/#django.db.models.ManyToManyField) の `through` 引数で中間モデルを指定した場合、管理画面はデフォルトではウィジェットを表示しません。これは、その中間モデルの各インスタンスは、単一のウィジェットで表示できる以上の情報を必要とし、複数のウィジェットに必要なレイアウトは中間モデルによって異なるからです。

しかし、インラインで情報を編集できるようにしたいと思うでしょう。幸いなことに、インライン 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)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["person", "group"], name="unique_person_group"
            )
        ]
```

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

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

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

次に `Person` と `Group` モデルの管理ビューを作成します:

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

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

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

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

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

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

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

```
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
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`](/ja/5.2/ref/contrib/contenttypes/#module-django.contrib.contenttypes.admin) によって提供される [`GenericTabularInline`](/ja/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.admin.GenericTabularInline) や [`GenericStackedInline`](/ja/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.admin.GenericStackedInline) （どちらも [`GenericInlineModelAdmin`](/ja/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.admin.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 のドキュメント](/ja/5.2/ref/contrib/contenttypes/) を参照してください。

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

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

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

admin テンプレートファイルは [django/contrib/admin/templates/admin](https://github.com/django/django/blob/stable/5.2.x/django/contrib/admin/templates/admin) ディレクトリにあります。

そのうちの一つ以上を上書きするには、まずプロジェクトの `templates` ディレクトリに `admin` ディレクトリを作成してください。これは `DjangoTemplates` バックエンドの [`DIRS`](/ja/5.2/ref/settings/#std-setting-TEMPLATES-DIRS) オプションの [`TEMPLATES`](/ja/5.2/ref/settings/#std-setting-TEMPLATES) 設定で指定したディレクトリのどれでもかまいません。 `'loaders'` オプションをカスタマイズしている場合は、 `'django.template.loaders.app_directories.Loader'` の前に `'django.template.loaders.filesystem.Loader'` が表示されていることを確認してください。そうすれば、 [`django.contrib.admin`](#module-django.contrib.admin) でインクルードされているテンプレートよりも先に、カスタムテンプレートがテンプレート読み込みシステムによって検出されます。

この `admin` ディレクトリの中に、アプリに対応した名前のサブディレクトリを作成します。これらのアプリのサブディレクトリの中に、モデルに対応した名前のサブディレクトリを作成します。 大文字と小文字を区別するファイルシステム上でアプリを実行する場合は、ディレクトリ名をすべて小文字にしてください、adminアプリはディレクトリを探すときにモデル名を小文字にします。

特定のアプリの管理テンプレートを上書きするには、 [django/contrib/admin/templates/admin](https://github.com/django/django/blob/stable/5.2.x/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` の例を示します:

```html+django
{% 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ページを作成するのに便利です。

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

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

インデックス、ログイン、ログアウトのテンプレートを変更したい場合は、独自の `AdminSite` インスタンス（下記参照）を作成し、 [`AdminSite.index_template`](#django.contrib.admin.AdminSite.index_template) 、 [`AdminSite.login_template`](#django.contrib.admin.AdminSite.login_template) 、 [`AdminSite.logout_template`](#django.contrib.admin.AdminSite.logout_template) プロパティを変更した方が良いでしょう。

## テーマのサポート

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

```html+django
{% 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](https://github.com/django/django/blob/stable/5.2.x/django/contrib/admin/static/admin/css/base.css) で定義されています。

[prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) メディアクエリを尊重したダークモード変数は [django/contrib/admin/static/admin/css/dark\_mode.css](https://github.com/django/django/blob/stable/5.2.x/django/contrib/admin/static/admin/css/dark_mode.css) で定義されています。これは `{% block dark-mode-vars %}` のドキュメントにリンクされています。

## `extrabody` ブロック

> **New in Django 5.2**

カスタムの HTML や JavaScript 、その他のコンテンツを、`admin/base.html` を継承するテンプレートの閉じる `</body>` タグの直前に表示させたい場合は、 `extrabody` ブロックを拡張することで実現できます。たとえば、ページ読み込み時にアラートを表示させたい場合、プロジェクトに `admin/base.html` のテンプレートオーバーライドを追加することで対応できます。

```html+django
{% extends 'admin/base.html' %}

{% block extrabody %}
    {{ block.super }}
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            window.alert('Welcome!');
        });
    </script>
{% endblock extrabody %}
```

## `AdminSite` オブジェクト

#### `class AdminSite(name='admin')`

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

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

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

#### `django.contrib.admin.sites.all_sites`

[`WeakSet`](https://docs.python.org/3/library/weakref.html#weakref.WeakSet) は全ての管理サイトのインスタンスを含んでいます。

### `AdminSite` の属性

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

#### `AdminSite.site_header`

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

#### `AdminSite.site_title`

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

#### `AdminSite.site_url`

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

サブパス上で動作しているサイトでは、 [`each_context()`](#django.contrib.admin.AdminSite.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`](#django.contrib.admin.ModelAdmin.empty_value_display) を参照してください。

#### `AdminSite.enable_nav_sidebar`

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

#### `AdminSite.final_catch_all_view`

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

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

#### `AdminSite.login_template`

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

#### `AdminSite.login_form`

admin サイトのログインビューで使用される [`AuthenticationForm`](/ja/5.2/topics/auth/default/#django.contrib.auth.forms.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`](#django.contrib.admin.AdminSite.site_header)
- `site_title`: [`AdminSite.site_title`](#django.contrib.admin.AdminSite.site_title)
- `site_url`: [`AdminSite.site_url`](#django.contrib.admin.AdminSite.site_url)
- `has_permission`: [`AdminSite.has_permission()`](#django.contrib.admin.AdminSite.has_permission)
- `available_apps`: [アプリケーションレジストリ](/ja/5.2/ref/applications/) から現在のユーザーが利用できるアプリケーションのリストです。リストの各エントリは以下のキーを持つアプリケーションを表す 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`](#django.contrib.admin.AdminSite.enable_nav_sidebar)
- `log_entries`: [`AdminSite.get_log_entries()`](#django.contrib.admin.AdminSite.get_log_entries)

#### `AdminSite.get_app_list(request, app_label=None)`

[アプリケーションレジストリ](/ja/5.2/ref/applications/) から、現在のユーザーが利用できるアプリケーションのリストを返します。オプションで `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_active`](/ja/5.2/ref/contrib/auth/#django.contrib.auth.models.User.is_active) と [`User.is_staff`](/ja/5.2/ref/contrib/auth/#django.contrib.auth.models.User.is_staff) の両方が `True` である必要があります。

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

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

モデルが抽象クラスの場合は [`ImproperlyConfigured`](/ja/5.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured) を、モデルが既に登録されている場合は `django.contrib.admin.exceptions.AlreadyRegistered` を発生させます。

#### `AdminSite.unregister(model_or_iterable)`

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

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

#### `AdminSite.get_model_admin(model)`

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

#### `AdminSite.get_log_entries(request)`

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

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

Django admin のセットアップの最後のステップは、 `AdminSite` インスタンスを URLconf にフックすることです。指定した URL を `AdminSite.urls` メソッドで指定します。 [`include()`](/ja/5.2/ref/urls/#django.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`](#django.contrib.admin.AdminSite) サブクラスを参照するようにします。

*`myapp/admin.py`*

```python
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`*

```python
from django.urls import path

from myapp.admin import admin_site

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

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

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

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

*`myproject/admin.py`*

```python
from django.contrib import admin

class MyAdminSite(admin.AdminSite): ...
```

*`myproject/apps.py`*

```python
from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = "myproject.admin.MyAdminSite"
```

*`myproject/settings.py`*

```python
INSTALLED_APPS = [
    # ...
    "myproject.apps.MyAdminConfig",  # replaces 'django.contrib.admin'
    # ...
]
```

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

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

このインスタンスでは、 `/basic-admin/` と `/advanced-admin/` はそれぞれ `AdminSite` インスタンス `myproject.admin.basic_site` と `myproject.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` インスタンスはコンストラクタに一つの引数、名前を渡します。この引数は [逆引き](#admin-reverse-urls) のためにURL名のプレフィックスとなります。これは複数の `AdminSite` を使用する場合にのみ必要です。

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

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

> **Note**
>
> 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`](/ja/5.2/ref/settings/#std-setting-AUTH_USER_MODEL) インスタンス）。

#### `LogEntry.content_type`

変更されたオブジェクトの [`ContentType`](/ja/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.models.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()`](#django.contrib.admin.models.LogEntry.get_change_message) が現在のユーザ言語で翻訳されたメッセージを再構成できるようにしています。カスタムコードではこれをプレーンな文字列として設定するかもしれません。この値を取得するには、直接アクセスするのではなく [`get_change_message()`](#django.contrib.admin.models.LogEntry.get_change_message) メソッドを使用することをお勧めします。

### `LogEntry` メソッド

#### `LogEntry.get_edited_object()`

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

#### `LogEntry.get_change_message()`

[`change_message`](#django.contrib.admin.models.LogEntry.change_message) を現在のユーザ言語に変換します。Django 1.10 より前に作成されたメッセージは、常にログに記録された言語で表示されます。

## admin の URL を逆引きする

[`AdminSite`](#django.contrib.admin.AdminSite) がデプロイされると、そのサイトが提供するビューは Django の [URL 逆引きシステム](/ja/5.2/topics/http/urls/#naming-url-patterns) を使ってアクセスできるようになります。

[`AdminSite`](#django.contrib.admin.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`](#django.contrib.admin.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` オブジェクト(投票アプリケーションから)の変更ビューへの参照を取得したい場合、次のように呼び出します:

```pycon
>>> 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` という名前の管理インスタンスから管理ビューを取得したい場合は、以下のように呼び出す必要があります。

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

詳細は [名前空間のURLの逆引き](/ja/5.2/topics/http/urls/#topics-http-reversing-url-namespaces) のドキュメントを参照してください。

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

```html+django
{% 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`](#django.contrib.admin.ModelAdmin) インスタンスの URL 名の最後の部分と一致します。変数 `opts` には `app_label` と `model_name` 属性を持つ任意のオブジェクトを指定することができ、通常は現在のモデルの管理ビューから提供されます。

## `display` デコレータ

#### `display(* (Keyword-only parameters separator (PEP 3102)), boolean=None, ordering=None, description=None, empty_value=None)`

このデコレータは [`list_display`](#django.contrib.admin.ModelAdmin.list_display) や [`readonly_fields`](#django.contrib.admin.ModelAdmin.readonly_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): ...
```
