Djangoの管理ページをカスタマイズする

Djangoの標準機能として管理ページがある。プロジェクトのsettings.py, urls.pyと、アプリの urls.py, models.py, admin.pyを少しいじるだけでデータの一覧表示に、各データのCRUDが容易にできる画面があっという間に使えるようになります。

環境が既にある方は、「管理画面のカスタマイズ」から読み進めてください。

目次

環境構築

dockerのalpineにパッケージを入れながら環境を構築していく手順にしています。このあたりDockerfileにしておくと次回から楽になりますが…今回はこのままお付き合いください(๑•̀ㅂ•́)و✧

$ mkdir -p ~/work/ap/
$ cd ~/work
$ docker run -it --rm --name django \
             -p 8010:8000 \
             -v ~/work/ap:/code \
             alpine \
             /bin/ash
/ # apk update
/ # apk add python3 py3-pip
/ # cd /code
/code # python3 -m venv ./venv
/code # source venv/bin/activate
(venv) /code # pip install --upgrade pip
(venv) /code # pip install django tzdata
(venv) /code # django-admin startproject testprj /code
(venv) /code # django-admin startapp testapp
(venv) /code # python manage.py showmigrations
(venv) /code # python manage.py makemigrations
(venv) /code # python manage.py migrate
(venv) /code # python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address:
Password:
Password (again):
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

/code/testprj/settings.py

ALLOWED_HOSTS = ['*']

<snip>

INSTALLED_APPS = [
    'testapp.apps.TestappConfig',
    
<snip>

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],

<snip>

TIME_ZONE = 'Asia/Tokyo'

開発サーバを起動します。

(venv) /code # python mange.py runserver 0.0.0.0:8000 &

ブラウザでアクセスしてみる。

http://127.0.0.1:8010/

管理画面にアクセスしてみる。

http://127.0.0.1:8010/admin/

モデルの作成

/code/testapp/models.py

from django.db import models

# Create your models here.

class Type(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256, verbose_name='装置名')
    panel = models.CharField(max_length=256, verbose_name='パネル名')
    pn = models.CharField(max_length=256, verbose_name='プロダクト番号')

    class Meta:
        verbose_name_plural = '機種マスター'

    def __str__(self):
        return self.name


class Host(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=256, verbose_name='ホスト名')
    sn = models.CharField(max_length=256, verbose_name='シリアル番号')
    type_id = models.ForeignKey(Type, on_delete=models.PROTECT)

    class Meta:
        verbose_name_plural = 'ホスト情報'

    def __str__(self):
        return self.name

モデルからデータベースを作成する。

(venv) /code # python manage.py check
(venv) /code # python manage.py makemigrations
Migrations for 'testapp':
  testapp/migrations/0001_initial.py
    + Create model Type
    + Create model Host
    
(venv) /code # python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, testapp
Running migrations:
  Applying testapp.0001_initial... OK

(venv) /code # 

標準のsqlite3にテーブルが作成されているか確認する

(venv) /code # python
>>> import sqlite3
>>> dbname = 'db.sqlite3'
>>> conn = sqlite3.connect(dbname)
>>> cur = conn.cursor()
>>> cur.execute("select name from sqlite_master where type='table';")
>>> print(cur.fetchall())
[('django_migrations',), ('sqlite_sequence',), ('auth_group_permissions',), ('auth_user_groups',), ('auth_user_user_permissions',), ('django_admin_log',), ('django_content_type',), ('auth_permission',), ('auth_group',), ('auth_user',), ('django_session',), ('testapp_type',), ('testapp_host',)]
>>> conn.close()

今回は、testappというアプリ内に HostとTypeというモデルを作成したので、testapp_host, testapp_typeが作成されている事を確認する。

管理画面の設定

作成したモデルを管理画面でCRUDできるようにadmin.pyに一覧表示する際のカラム名や、検索対象のカラムの設定などをしていきます。

/code/testapp/admin.py

from django.contrib import admin

# Register your models here.

from .models import Host, Type

class TypeAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'panel', 'pn',)
    list_filter = ('panel',)
    search_fields = ('name', 'panel', 'pn',)
    list_per_page = 15
admin.site.register(Type, TypeAdmin)


class HostAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'sn', 'type_id__name', 'type_id__panel', 'type_id__pn',)
    list_filter = ('type_id__panel',)
    search_fields = ('name', 'sn', 'type_id__name', 'type_id__panel', 'type_id__pn',)
    list_per_page = 15
admin.site.register(Host, HostAdmin)

ブラウザで管理画面にアクセスすると以下のように「ホスト情報」と「機種マスター」が表示されているはず。

http://127.0.0.0:8010/admin/

では、「+Add」ボタンを押して幾つかデータを作成していきます。まずはじめに「機種マスター」から登録し、作成した機種マスターを選択しつつ「ホスト情報」を登録するようにします。

機種マスターの登録例

ホスト情報の登録例

管理画面のカスタマイズ

リスト表示画面のカスタマイズ

では、本題の管理画面のカスタマイズに取り掛かります。まず初めに、リスト表示時にFILTERが結構幅を利かせており普段使わない時は引っ込んでおいて欲しいなぁと感じます。管理画面の左ペインは実は画面左端の「<<」という記号を押すと左に収納され画面を広く使うことが出来るようになります。これと同じイメージで作ってみます。

管理画面のHTMLはプロジェクト直下の「templates/admin/」以下にルールに従ってテンプレートファイルを設置することにより行うことが出来ます。

まずはリスト表示時のFILTERについて以下のようにファイルを作成してみてください。

(venv) /code # mkdir -p /code/templates/admin/testapp/host/

このパスは「プロジェクトルート/templates/admin/アプリ名/モデル名/」となっています。

/code/templates/admin/testapp/host/change_list.html

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

{% block extrahead %}
    {{ block.super }}
    <style>
        #changelist-filter {
            margin: 0 !important;
        }
    </style>
{% endblock %}

{% block content %}
    {{ block.super }}
{% endblock %}

{% block footer %}
    {{ block.super }}
    <script type="text/javascript">
        (function($) {
            $(function() {
                const $filterDiv = $('#changelist-filter');
                if (!$filterDiv.length) return;

                const $button = $('<div>≪</div>');
                $filterDiv.hide();
                $filterDiv.before($button);

                $button.on('click', function () {
                    $filterDiv.toggle();
                });

                $('#changelist-filter details').removeAttr('open');
            });
        })(django.jQuery);
    </script>
{% endblock %}

こんな感じでLIST_FILTERの部分が開閉するようになります。

Guicornの導入

開発用runserverでは性能が出ないので本番運用で使う時にはgunicornなどを用います。以下に導入方法を示します。

(venv) /code # pip install gunicorn
(venv) /code # 

アプリの保存と起動スクリプト

$ docker commit django ap:latest
$ cd ~/work/ap
$ vi run.sh
---
#!/bin/bash

docker run --rm --name ap \
        -p 8010:8000 \
        -v ~/work/ap:/code \
        ap:latest \
        /code/ap.sh
---

$ chmod +x run.sh
$
$ vi ap.sh
---
#!/bin/ash

cd /code \
&& source ./venv/bin/activate \
&& gunicorn --bind 0.0.0.0:8000 --timeout 600 testprj.wsgi
---

$ chmod +x ap.sh
$
$ ./run.sh &
[2025-04-06 14:18:46 +0000] [7] [INFO] Starting gunicorn 23.0.0
[2025-04-06 14:18:46 +0000] [7] [INFO] Listening at: http://0.0.0.0:8000 (7)
[2025-04-06 14:18:46 +0000] [7] [INFO] Using worker: sync
[2025-04-06 14:18:46 +0000] [8] [INFO] Booting worker with pid: 8

投稿日

カテゴリー:

投稿者: