djangoの管理サイトについてまとめる

管理サイトとは
-
レコードの追加や削除などを行うことのできるサイト。

djangoにおいてプロジェクトの作成時から用意されている。

サイトへのアクセスは`admin/`というURLで行うことができる(urls.pyにて最初から定義されている）。

管理ユーザー
-
管理サイトにアクセスするためのアカウントは、以下のターミナルコマンドで作成することが一般的。

```shell
% python manage.py createsuperuser
```
上記のコマンドを実行するとユーザー名・メールアドレス・パスワードを聞かれるので、それらを入力すると権限ユーザーが作成される。

権限ユーザーとユーザーモデルの関係
-
管理サイトへログインするためのアカウント（＝権限ユーザー）とdjangoアプリケーションを利用するためのアカウント（＝ユーザーモデル）は別々の存在ではなく同じものである。

権限ユーザーの実態は、`is_superuser`という属性値が`true`のユーザーインスタンスであり、`users = get_user_model().objects.all()`などとした中にも含まれることになる。

逆に言えば、`createsuperuser`コマンドではなく管理サイトやアプリケーション内で作成したユーザーインスタンスであっても条件（後述）さえ満たせば管理サイトへのログインが可能。

管理サイトへのアクセス権限
-
上記の通り、通常の手順で作成したユーザーであっても特定の条件を満たせば管理サイトへのアクセスが可能。

その条件とは、「`is_staff=true`もしくは`is_superuser=true`」である(`is_staff`と`is_superuser`はいずれもAbstractUserクラスにデフォルトで用意されている）。

`is_superuser=ture`にしてしまうと全ての権限を持った状態になってしまうため、管理サイトへのログインのみを許可したい場合には`is_staff=true`を用いる。

管理サイトへのモデルの追加
-
最初に述べた通り管理サイトではレコードの追加・編集・削除などが可能であるが、これらの作業をするためにはまずそのモデルを管理サイトでの操作対象として追加する必要がある。

管理サイトでどのモデルを操作できるかは各アプリケーションフォルダごとの`admin.py`というファイルで定義されており、ここに以下のように記述することでそのモデルを管理者サイトで操作することが可能となる。

```python:book/admin.py
from .models import Book

admin.site.register(Book)
```

`admin.site.register`の引数として与えたモデルは管理サイトで扱えるようになる。

今回はBookというモデルを指定している。

管理サイトでできること
-
上記の手順でモデルを追加すると、そのモデルのレコードの一覧表示・追加・編集・削除が可能になる。

また、それら以外の操作を追加したり、一覧表示画面で表示される内容を変更することも可能（後述）。

管理サイトでのレコードの表示形式
-
管理サイトでレコードを一覧表示した場合のレコードの表示名はモデルごとの`__str__`メソッドの戻り値になる。

`__str__`メソッドを定義しなかった場合は`モデル名 object(pk)`となる。

```python:レコード表示名の例
# Bookモデルに{ "id": 1, "title": "坊ちゃん", "author_name": "夏目漱石" }というレコードがあった場合。

# デフォルトの表示
# Book object(1)

# __str__メソッドを定義
def __str__(self):
  return f'{self.title}({self.author_name})'

# 表示名が以下に変更される
# 坊ちゃん（夏目漱石）
```

操作内容の追加
-
管理サイトで行える操作を追加したい場合の操作手順は以下の通り。

- `admin.ModelAdmin`クラスを継承したモデルを新しく定義する。
- そのモデルのインスタンスメソッドとして、追加したい操作を定義する。
- モデルの属性値`actions`の値として、上記の関数を設定する。
- モデルを`admin.site.register`の中に追加する。

```python:admin.py
from django.contrib import admin
from .models import Campaign

class CampaignAdmin(admin.ModelAdmin):
  # 追加したい操作を関数として定義
  def hard_delete(self, request, queryset):
    queryset.delete(hard=True)
  # 関数を追加
  actions = [hard_delete]
  # 関数の表示名を設定
  hard_delete.short_desciption = "物理削除"

admin.site.register(Campaign, CampaignAdmin)
```

上記の例ではキャンペーンモデルの物理削除を登録しています。

管理サイトで選択したインスタンスが`queryset`の中に入るので、それに対して処理を実行している形ですね。

余談ですが、論理削除を実装したモデルに関しては管理サイトでの削除も論理削除に置き換わるので、上記のように自分で物理削除を追加する必要があります。

表示内容の追加
-
レコードの一覧表示画面での表示形式は`__str__`メソッドで定義されているが、それとは別に`list_display`という属性値を用いて決定することも可能。

```python:admin.py
from django.contrib import admin
from .models import Campaign

class CampaignAdmin(admin.ModelAdmin):
  def hard_delete(self, request, queryset):
    queryset.delete(hard=True)
  actions = [hard_delete]
  hard_delete.short_desciption = "物理削除"
  # 表示内容の設定（フィールド名を指定すれば良い）
  list_display = ["datetime", "order"]

admin.site.register(Campaign, CampaignAdmin)
```

初期状態の表示
[![Image from Gyazo](https://i.gyazo.com/e9bdb74a231b9d9a59ebf0486b69f897.png)](https://gyazo.com/e9bdb74a231b9d9a59ebf0486b69f897)

`__str__メソッド`で表示を変更
[![Image from Gyazo](https://i.gyazo.com/2abdab054b06d5daacb6c5e583a4c81f.png)](https://gyazo.com/2abdab054b06d5daacb6c5e583a4c81f)

`list_display`を利用
[![Image from Gyazo](https://i.gyazo.com/e644beb770829de186d3cdab363edd4e.png)](https://gyazo.com/e644beb770829de186d3cdab363edd4e)

個人的な印象ですが、外部キーが絡む場合は`__str__`メソッドを用いた方が表示内容の自由度が高いかなと思います。