Django管理サイト、一覧表示をカスタマイズ

Python Django

概要

次のような、ブログの記事を表現しているモデルがあります。

from django.db import models
from django.utils import timezone


class Post(models.Model):
    title = models.CharField('タイトル', max_length=30)
    thumbnail = models.ImageField('サムネイル')
    text = models.TextField('本文')
    is_public = models.BooleanField('公開可能か', default=True)
    created_at = models.DateTimeField('作成日', default=timezone.now)
    updated_at = models.DateTimeField('更新日', default=timezone.now)

    def __str__(self):
        return self.title

タイトル、サムネイル画像、本文、公開フラグ、作成日、更新日があります。

Django管理サイトでは、通常次のように表示されますが...

通常の表示

それだと見づらいので、今回は次のように、わかりやすく表示させる方法を紹介します。

わかりやすく表示

こういったカスタマイズは、admin.pyで行うことができます。まず、次のようにしておきましょう。

from django.contrib import admin
from .models import Post


class PostAdmin(admin.ModelAdmin):
    pass


admin.site.register(Post, PostAdmin)

普段はadmin.site.register(Post)のようにしますが、今回はadmin.site.register(Post, PostAdmin)とします。第二引数に指定したクラスで、色々なカスタマイズを行っていきます。

一覧表示の項目追加

まず、一覧表示の項目を増やしてみましょう。クラス属性list_displayに指定します。

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'text', 'is_public', 'created_at', 'updated_at')

これは見た感じわかると思いますが、タイトル、本文、公開フラグ、作成日、更新日といった情報を表示するようにしています。

一覧表示

並び替え機能の追加

一覧の並びを変更したい場合は、ordering属性を使います。

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'text', 'is_public', 'created_at', 'updated_at')
    ordering = ('-created_at',)

絞り込み機能の追加

例えば公開フラグがTrueの記事だけ表示する、Falseの記事だけ表示する、ということをしたくなるかもしれません。これも簡単で、list_filter属性に書いていくだけです。

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'text', 'is_public', 'created_at', 'updated_at')
    ordering = ('-created_at',)
    list_filter = ('is_public',)

すると、画面の右側で次のように表示されます。

絞り込み欄

検索機能の追加

自分で作ると少し面倒な検索機能も、簡単に作れます。

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'text', 'is_public', 'created_at', 'updated_at')
    ordering = ('-created_at',)
    list_filter = ('is_public',)
    search_fields = ('title', 'text')

上は、「タイトルか本文に含まれているか」を検索する指定です。

検索欄

プレビュー画像の追加

今回のモデルでは、thumbnailという記事サムネイルのためのImageFieldがありました。この画像をプレビューさせると、わかりやすくなりそうです。

from django.contrib import admin
from django.utils.safestring import mark_safe
from .models import Post


class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'thumbnail_preview', 'text', 'is_public', 'created_at', 'updated_at')
    ordering = ('-created_at',)
    list_filter = ('is_public',)
    search_fields = ('title', 'text')

    def thumbnail_preview(self, obj):
        return mark_safe('<img src="{}" style="width:100px; height:auto;">'.format(obj.thumbnail.url))

    thumbnail_preview.short_description = 'プレビュー'


admin.site.register(Post, PostAdmin)

まずですが、list_displayにて'thumbnail_preview'を追加しておきます。thumbnail_previewなんてフィールドは作ってないぞ?thumbnailの書き間違いでは?と思うかもしれませんが、これで良いのです。thumbnailフィールドを直接書いても、プレビュー表示はしてくれません。なので、プレビュー用のカスタム項目を作っている訳です。

カスタム項目の作り方ですが、list_displayにはモデルフィールド名のほか、自作の呼び出し可能オブジェクトも渡すことができて、凝った項目を作りたい場合はこれが便利です。今回はthumbnail_previewというメソッドを作り、それをlist_displayに指定しています。

thumbnail_previewメソッドのobj引数ですが、これはPostモデルインスタンスが渡されます。なので、obj.thumbnailでその記事のサムネイルフィールドにアクセスができます。

画像をHTML上で表示するので、<img src="/media/a.png">のようなimg要素を返す必要があります。src部分の画像パスは、obj.thumbnail.urlでアクセスできます。ImageField.url ですね。DjangoにHTMLを変数として渡すとエスケープされてしまうので、django.utils.safestring.mark_safeを使い、エスケープしないようにしておきます。style="width:100px; height:auto;"は、ちょっとした見た目の調整です。

今作ったプレビュー用のカスタム項目名は、thumbnail_preview.short_description = 'プレビュー'のように設定できます。

これで、次のようにプレビューが表示されました!

わかりやすく表示

Relation Posts

関連記事はありません。

Comment

記事にコメントする

まだコメントはありません。