サイドバーの「Django ドキュメント検索」というプレースホルダの入った検索では、Django ドキュメント (Django 2.1) の公式サイト内を検索できます
Django チュートリアルの進め方 その 7

目次

はじめに

Django を学習するには、何はともあれ公式チュートリアル「はじめての Django アプリ作成」からスタートしてみるのが良いでしょう。しかし、いざチュートリアル通りに進めようとしても躓く場合も多いと思います。そこで、「チュートリアルの進め方」シリーズとして、チュートリアルに沿った作業を行いながら補足事項をまとめることにしました。チュートリアルで躓いた際のヒントとしてお使いください。

利用環境は Ubuntu、 Linux Mint を中心として説明しますが、 Windows についても補足します。
前回は、Django チュートリアルの進め方 その 6 と題してはじめての Django アプリ作成、その 6についてまとめました。今回は、はじめての Django アプリ作成、その 7 についてです。

admin フォームのカスタマイズ

チュートリアル その2 では、Question モデルを管理サイトでメンテナンスできるようにしました。その際には、polls/admin.py に admin.site.register(Question) を記入しました。この時、Question の質問項目 What's up? のメンテナンス画面は下記の様になっていました。

今回のチュートリアルでは、この管理サイトを編集してゆきます。

上記の編集フォームの並び順を変えるには、admin.ModelAdmin を継承した adminクラスを定義して regsiter の第2引数に渡します。

from django.contrib import admin

from .models import Question


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


admin.site.register(Question, QuestionAdmin)

 

fields 属性でフィールドの並び順を指定してするわけです。http://localhost:8000/admin/ から Question > What's up? をクリックしてみます。

次に、フィールドをフィールドのグループ (フィールドセット) に分けてみます。

from django.contrib import admin

from .models import Question


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


admin.site.register(Question, QuestionAdmin)

http://localhost:8000/admin/ から Question > What's up? をクリックしてみます。

question_text と pub_date が異なるグループ (フィールドセット) として表示されています。

リレーションを張ったオブジェクトの追加

Question に加えて Choice も管理画面に追加します。polls/admin.py に register(Choice) を追加します。

from django.contrib import admin

from .models import Question, Choice


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


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

http://localhost:8000/admin/ を確認します。

Choice の右にある + 追加をクリックしてみます。

この画面を使って Choice を追加する事ができます。また、Question のドロップボックス右にある + をクリックして Question を追加できます。
一方で、Question (質問) の追加画面は下記のようになっています。

Choice (回答) の追加画面から Question (質問) を追加できるのは便利ですが、実際には Question (質問) の追加画面の方で Choice (回答) を登録したいところです。しかし、現状では  Question (質問) を追加することしかできません。
チュートリアルにしたがって StackedInline クラスを定義して inlines として指定してみます。

from django.contrib import admin

from .models import Choice, Question


class ChoiceInline(admin.StackedInline):
    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)

表示するモデルと、表示するレコード数を指定した admin.StackedInline クラスを定義し、QuestionAdmin で inlines として渡してあげるだけです。

http://localhost:8000/admin/ から Question 右の +追加をクリックしてみます。

Question の追加画面で Choice を3つ追加できるようになりました。足りない場合は、+Choiceの追加 から追加が可能です。StackedInline は表示領域を大きくとってしまうので、コンパクトに表示できる TabularInline にしてみます。

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)

Question の追加画面を表示します。

1つの Choice (質問) が1行で表示されるようになったので、コンパクトな表示になりました。

管理サイトのチェンジリストページをカスタマイズする

管理サイトのQuestionチェンジリスト (Question の変更ページ) を表示します。管理サイトで Questions 右の「変更」をクリックします。

Question の列に表示されている What's up? は、Question モデルの __str__() によって表示されているものです。(デフォルトの動作)
これをフィールド値を表示するように修正します。(属性の他にメソッドも指定できます。)

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

画面を確認します。

was_published_recently はメソッド値のため、ソートができなかったりタイトル表記がメソッド値になっています。これらの動作を変更するために、メソッドに属性を付加することができます。

.
.
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?'
.
.
admin_order_field 属性
ソート時に指定したフィールドで並べ替える。
フィールド名に '-' をつけると降順にソートできる。
(例) was_published_recently.admin_order_field = '-pub_date'
boolean 属性
与えられた文字列が、モデルのメソッド、True か False を返す ModelAdmin、callable のどれかの場合、boolean 属性を True にすると、on/off に対応したアイコンを表示する。
short_description 属性
callable、モデルメソッド、ModelAdmin のいずれかを使っているとき、short_description 属性を追加することでカラムのタイトルをカスタマイズできる。

表示は下記のようになります。

次に、pub_date にフィルター機能を追加します。QuestionAdmin に list_filter を指定します。

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

画面表示は下記のようになります。

右側に「date published で絞り込む」というフィルタ機能が追加されました。pub_date フィールドのラベル名 date published がフィルタ名として使われている事も確認できます。
さらに question_text で検索できるようにしてみます。search_fields を指定します。

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

画面は下記のようになります。

上部に検索欄が追加されました。

管理サイトのルック & フィールをカスタマイズする

ここからは管理サイトのデザインを修正していきます。

プロジェクト テンプレートをカスタムする。

管理サイトのテンプレートをプロジェクト内にコピー、修正してそれを管理画面で使用するようにします。まず、プロジェクトルート(manage.py が置かれているディレクトリ) に templates ディレクトリを作成します。この時点のディレクトリ構成は下記のようになります。

├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── __pycache__
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── polls
│   ├── __init__.py
│   ├── __pycache__
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   ├── models.py
│   ├── static
│   │   └── polls
│   │       ├── images
│   │       │   └── background.gif
│   │       └── style.css
│   ├── templates
│   │   └── polls
│   │       ├── detail.html
│   │       ├── index.html
│   │       └── results.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
└── templates

現状の設定では、Django は各アプリケーション内の templates ディレクトリからテンプレートを探すようになっています。今作成したプロジェクト直下の templates ディレクトリを検索パスに含めるため、settings.py の TEMPLATES オプションに DIRS オプションを追加します (デフォルトではリストの中身が空になっています)。

.
.
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
.
.

先程作成した templates ディレクトリの下に admin ディレクトリを作成し、Django のインストールディレクトリにある django/contrib/admin/templates/admin/base_site.html をコピーします。
このファイルを開くと下記のようになっています。

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

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}

管理画面のサイト名の表示を変えるには、6行目の後ろの方にある {{ site_header|default:_('Django administration') }} の部分を適当な文字列に変えます。ここでは、Polls Administration に置き換えます。

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

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}
置換前のテンプレートタグ

{{ site_title|default:_('Django site admin') }}

このタグは {{ site_title ... }} の形式ですので、site_title という変数値の表示を指示しています。
|default: はフィルタの記述で、site_title が定義されていなかった場合に _('Django site admin') を表示することになります。
_( ... ) の表記は国際化対応の記述になりますので、日本語環境であれば 'Django site admin' に対して予め定義された日本語文字列が表示されます。

ここでは、これらの表記を、ベタな文字列 'Polls Administration' に置き換えています。

この例では、管理サイトテンプレートの修正を行っていますが、単に管理サイトのタイトルを書き換えるだけなら、チュートリアルに記述があるように、django.contrib.admin.AdminSite.site_header の値を 'Polls Administration' に設定した方が早いです。その場合には、setting.py で値を設定すれば良いでしょう。

from django.contrib.admin import AdminSite
AdminSite.site_header = 'Polls Administration'

いずれの方法でも、管理画面の表示は下記のようになります。

TEMPLATES の DIRS を書き換えておくと、管理サイトのテンプレートをコピーするだけで修正できるのはとても便利ですね。

アプリケーション用の テンプレートをカスタマイズする

チュートリアルでは、アプリケーションが複雑になってきた場合、上記のように admin テンプレートをプロジェクトにコピーして修正するのでなく、アプリケーションのテンプレートを編集した方が良いとの説明です。これは、アプリケーションのテンプレートディレクトリ内に admin ディレクトリを作成してそこに admin 用テンプレートを配置するということかな?まだ検証していません。

admin index ページをカスタムする

先程の base_site.html と同様に index.html の app_list を展開しているところを、ハードコードして、各アプリ毎のカスタマイズページを作成できるとのこと。ここまでさわる必要が出てくるのはかなりあとになってからでしょうか。

ゲームを作りながら楽しく学べるPythonプログラミング (Future Coders(NextPublishing))

参考

低価格なのに高速・多機能・高セキュリティ 月額400円(税別)から最大容量100GB WordPress専用高速サーバー Z.com WP
おすすめの記事