Pythonでのチームアプリ開発に参画するための学習履歴~Djangoチュートリアル7~

# はじめに

Djangoチュートリアルもこれで基本的な部分は最後となります。
最後は、アプリの管理ページのカスタマイズについて少し見ていきましょう。
DjangoにはXAMPPでいうphpMyAdminのようにSQLを使わなくてもブラウザでテーブルにレコードの追加や更新・削除を行えるadminフォームという機能があるのでそれをカスタマイズしていきます。


# 基本的なカスタマイズ

```polls/admin.py

from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)

```

`QuestionAdmin`クラス以下がカスタム内容です。
つまり、モデルごとにクラスを作ることで各テーブルごとにカスタム内容を変えることができるわけです。
`fields`でマイグレーションで作成したテーブルの各カラム名を指定します。このとき左から順に実際の表示位置では表示されます。
次にフィールドを増やしてみましょう。

```python


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

```

`fields`を`fieldsset`にして`(フィールド名, {'fields': ['カラム名']})`と設定してあげるとこのカラムはどの情報だよという表示にすることができます。
例えば` ('Date information', {'fields': ['pub_date']})`なら`pub_date`は`Date information(日付に関する情報)`だよという表示にすることができます。


# リレーションしたテーブルのオブジェクトを追加する

```python


from .models import Choice, Question
# ...
admin.site.register(Choice)


```
`Choice`モデルをインポートし`admin.site.register(Choice)`を追加します。
こうすることで`Choice`モデルを編集できるようになります。
ですが、今回は1つの質問に対して複数の答えがあるといったリレーションなので、`Question`オブジェクトを追加する際にそれに付随して`Choice`オブジェクトを追加できた方が都合がいいのでそのように変更してみます。


```python


from django.contrib import admin

from .models import Choice, Question


class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 3


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)


```

`ChoiceInline`クラスでリレーション先のモデルとデータ数を設定します(上の例だと1つの`Question`オブジェクトに対して、`Choice`オブジェクトを3つ分のフィールドが用意される)。
引数に`TabularInline`を指定すると`phpMyAdmin`のようなテーブル形式の見た目に変更できます。
`'classes': ['collapse']`を指定したフィールドは折りたたまれた状態で表示されます。
`inlines = [ChoiceInline]`で先程の`ChoiceInline`クラスを指定します。

# モデルのインデックスにあたるページをカスタマイズする

実はデフォルトのままだとモデルのレコードの一覧にあたるページ(Djangoでは`Change List`と呼ばれるみたいです)にはカラムが1つしか表示されません。
これでは不便なのでレコードのカラムをすべて表示できるようにしましょう。
`admin.py`の`QuestionAdmin`クラスに下記の項目を追加していきます。

```polls/admin.py

# Change Listで表示するカラムの指定

list_display = ('question_text', 'pub_date', 'was_published_recently')


```

```polls/models.py


class Question(models.Model):
	# 中略
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'


```

`models.py`の`was_published_recently()`メソッドを上記のように修正します。
メソッドに属性をつけることでさらに細かくカスタムすることができます。
例えば`short_description`を指定するとカラムの名前を指定したものに変更する事ができます。
`admin_order_field`にカラム名を指定すると、そのカラムに対してソート(フィルター)をブラウザ上で行えるようになります。
`boolean`属性を指定すると`True or False`の代わりに○×のアイコンが表示されます。
`was_published_recently`は`True or False`の値を持つのでその代わりにアイコン表示になるということですね。
では再び`admin.py`に戻ります。

```polls/admin.py


from django.contrib import admin
from .models import Question, Choice

# Register your models here.

class ChoiceInline(admin.TabularInline):
	model = Choice
	extra = 3

class QuestionAdmin(admin.ModelAdmin):
	list_display = ('question_text', 'pub_date', 'was_published_recently')
	fieldsets = [
		(None,			{'fields': ['question_text']}),
		('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
	]
	inlines = [ChoiceInline]
	list_filter = ['pub_date']
	search_fields = ['question_text']

admin.site.register(Question, QuestionAdmin)
# admin.site.register(Choice)

```

`list_filter = ['pub_date']`の設定は先程の`admin_order_field `の設定と合わせてフィルターサイドバーを表示するようにする設定です。
`search_fields = ['question_text']`は検索ボックスを表示するようにする設定です。
こうすると、`Change List`中でこの場合は`question_text`カラムを検索ボックスに入れた検索語で検索できるようになります。

# 最後に

これでDjangoチュートリアル全7章完遂です。
しかしここまではあくまで基本で例えばこのチュートリアル1つとっても補足の章としてテストとデプロイ・再利用の章がありますし、この章の管理画面のカスタマイズにしても、テンプレートの使用やCSSの適用、管理機能のさらなる詳細設定など色々ありますのでまだまだやらなければならないことは多いです。

完走した感想はというと、Pythonという言語も含めてDjangoは1からプログラミングを始めた人にとってはやや理解が難しいところがあるとは思いますが、逆に他の言語を習得できている人からすると確かに学習コストを少なく習得できるのかもしれないなという手応えは感じています。
これからチーム開発企画を含めて、自分で制作物を作っていきつつさらに理解を深めていきたいと思います。


# 参考

[[Python] Django 管理サイトのカスタマイズ（表示面）](https://qiita.com/okoppe8/items/702dab51e4db5d0ed677)
[Django 管理画面逆引きメモ]https://qiita.com/zenwerk/items/044c149d93db097cdaf8)
[Djangoドキュメント](https://docs.djangoproject.com/ja/3.0/intro/tutorial07/)