はじめに
こんにちは、サイオステクノロジーのあさりです。今回は、PythonのWebフレームワークであるDjangoに組み込まれているDjango Adminに独自のページを追加する方法を紹介します。内容としては、DjangoAdminのモデル一覧画面におけるIDのリンク先をデフォルトの編集画面から独自で作成した詳細画面に遷移するようにしたいと思います。
環境
- Python3.11
- Django4.2
前提
独自のページを追加するにあたって何らかのモデルが必要となります。今回は、プロジェクト内にmyappというアプリケーションが存在し、myapp/models.pyに次のような「Book」モデルが定義されており、データベースに反映、myapp/admin.pyで管理画面に追加済みである想定です。プロジェクトの作成から管理画面への追加についてはこちらの記事を参考にしてみてください。
# myapp/models.py
from django.db import models
class Book(models.Model):
class Meta:
db_table = 'book'
verbose_name = '本'
title = models.CharField(verbose_name = 'タイトル', max_length=100)
author = models.CharField(verbose_name = '著者', max_length=100)
# myapp/admin.py
from django.contrib import admin
from .models import Book
class BookAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'author')
admin.site.register(Book,BookAdmin)
Django Adminに独自のページを追加する
今回は以下のID部分のリンク先をデフォルトの編集画面から独自で作成した詳細ページに遷移するようにしたいと思います。
独自ページ追加は以下の3つのステップで行います。
- ビュー関数の作成
- テンプレートの作成
- URLパターンの登録
それでは実際に実装していきましょう。
ビュー関数の作成
ビューは自作もできますが、今回は単一のオブジェクトの詳細を表示するためのDetailViewという組み込みビューを使用します。DetailViewは、特定のモデルのインスタンスを取得し、それをテンプレートに渡します。それでは、myapp/views.pyで次のようなビューを作成しましょう。
# myapp/views.py
from django.views.gneric import DetailView
from .models import Book
class BookDetailView(DetailView):
model = Book #参照するモデルを指定
template_name = 'admin/myapp/book_detail.html' #データを渡すテンプレートを指定
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# fieldsに各フィールドのverbose_nameとフィールド値を格納
context['fields'] = [(field.verbose_name, getattr(self.object, field.name)) for field in Book._meta.fields]
return context
テンプレートの作成
先ほどのビューからデータを受け取るテンプレートを作成していきます。今回はプロジェクト直下にtemplates/adminフォルダを作成し、そこにbook_detail.htmlファイルを置きます。
{% extends "admin/base_site.html" %}
{% load static %}
{% block content %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}">
</head>
<body>
<h1>Book Details</h1>
<!-- フィールド名とその値を表示します -->
{% for name, value in fields %}
<p>
<strong>{{ name }}:</strong> {{ value|default:"" }}
</p>
{% endfor %}
</body>
</html>
{% endblock %}
一行目でadmin/base_site.htmlを継承することにより、管理画面のヘッダーをつけることができます。今回の詳細画面ではビューから受け取ったfieldsを使って、「フィールド名:値」の形で表示されるようにしています。
次に独自に作成したtemplatesディレクトリが参照されるように、設定ファイルのTEMPLATESを次のように編集してください。
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'), # templatesディレクトリを追加
],
'APP_DIRS': True,
...
},
]
URLパターンの登録
独自のURLパターンの登録は、ModelAdminのget_urlsメソッドをオーバーライドすることで可能です。今回は次のようにURLパターンと呼び出されるビューを登録しました。また、一覧画面でのIDのリンク先を詳細画面とするlink_to_detailメソッドを定義し、一覧画面で表示するフィールドとして設定しています。
# myapp/admin.py
from django.contrib import admin
from django.urls import path, reverse
from .models import Book
from .views import BookDetailView
class BookAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
# URLパターンの登録
my_urls = [
path('<int:pk>/detail/', self.admin_site.admin_view(BookDetailView.as_view()), name='detail_view'),
]
return my_urls + urls
# 一覧画面でIDのリンク先として詳細画面を指定
def link_to_detail(self, obj):
link = reverse("admin:detail_view", args=[obj.pk])
return format_html('<a href="{}">{}</a>', link, obj.pk)
link_to_detail.short_description = 'ID'
link_to_detail.admin_order_field = 'id' #idに基づくソートの指定
#表示するフィールドの指定
list_display = ('link_to_detail', 'title', 'author')
...
これで”/myapp/book/1/detail”のような形でアクセス可能となります。実装としては以上になります。サーバーを立ち上げてID部分を押下した際に詳細画面に遷移するか確かめてみてください。以下のようなページが表示されたら成功です。
おわりに
今回は、DjangoAdminに独自のページを追加する方法を紹介しました。今回はDetailViewを用いて単一モデルの詳細情報を取得しましたが、Djangoには他にもモデル一覧を取得するListViewなど便利なクラスが用意されているので、試してみてください。