Django 管理システムをBootstrapで再設計する方法

Djangoの管理サイトは素晴らしい—機能が充実していて、使いやすく、設計上セキュリティが強固で、非常に信頼性が高い…しかし、ある程度は醜いという点が、ウェブサイトの他の部分とのデザインの統一性を考えるとデメリットになりかねません。その問題を解決しましょう。

壊れていなければ…

The default Django admin. (Source)

たとえば、あなたがDjangoとVue.jsでウェブアプリのプロトタイプを作成したばかりだとしましょう。多くのケースでは、Djangoの管理サイトをそのままバックオフィス用途に使用し、適切な権限設定を行った後、クライアントに引き渡すだけで十分です。結局のところ、それは完全に機能し、組み込みツールで多くの状況に対応するために大幅にカスタマイズできます。

では、なぜ煩わしいことをするのでしょうか?

管理サイトのデザインを変更する理由

しかし、統合をさらに進める正当な理由がいくつかあります。

  • ブランディング: 会社の名前と色を使用することを希望するのは何ら問題ありません。「Django administration」の代わりに(そして記録として、これはDjangoのBSDライセンスに適合しています)。
  • メインサイトと管理者サインインの無縫な統合: サイトを閲覧しながらバックオフィス機能を切り替えたい場合や、その逆の場合に、共通のナビゲーションバーを持つことができます。
  • 美化: 管理者画面はまあまあで、v2からレスポンシブウェブデザインの原則を実装しており(モバイルとデスクトップの両方でうまく機能します)、たくさん洗練されたスタイルシートでさらに良く見えるようになります。
  • バイパス機能: また、管理者用にカスタムドロップダウンメニューを作成して、実際に使用するオプションを表示し、ユーザーインターフェースから不要なものを非表示にすることもできます。これにより、より良いユーザーエクスペリエンスが実現します。

A Practical Example

この例では、繰り返さないために、DjangoとVue.jsでWebアプリをプロトタイプ化という記事で始めたシンプルな出版Webアプリケーションを再開します。

要するに:

  • a Django app with two models:
  • 記事フィールド名前著者(リンク)、内容スラッグ
  • 著者: フィールド名前スラッグ
  • A single view called frontend that queries all registries in both models.
  • A single template called template.
  • Vue.jsVue RouterVuexを実装して反応型でスケーラブルなインターフェースを構築します。

この回ではVue.jsの統合に特にこだわらず、ここでは変更しません。

基本テンプレート

Source

Djangoテンプレートは非常に多機能で強力で、アプリケーションレベル(Djangoサイトのコンポーネント)やサイトレベルで作成でき、さらにはDjangoに付属するテンプレートを上書きすることも可能です(ここではそうします)。

Source

基本的なテンプレートを作成し、BootstrapのJavaScriptとスタイルシート、そしてその補助ツールであるjQueryPopperにリンクしました。

これが、メインサイトで使用する基本テンプレートです。他のどのDjangoサイトでも通常使用するものと大差ありません:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

    <title>Django and Vue.js</title>
  </head>
  <body class="bg-light">
    <div class="bg-white container">
      <h1>Prototyping a Web App with Django and Vue.js</h1>

      <!-- Content -->
    </div>

    <!-- Vue.js -->
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/vue-router"></script>

    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

次に、これを管理者用に統合し、メインサイトとバックオフィスの両方にシェアドナビゲーションバーを追加します!

メインUIテンプレートの管理者への統合

前述の通り、テンプレートをオーバーライドできます。これには管理者のテンプレートも含まれます。ただし、Djangoの設計上、メインサイトとバックオフィスはそれぞれ独自のテンプレート、スタイルシート、contribパッケージを持つ2つの異なるシステムであるため、ほぼ同一であっても、ほぼ同一であっても、メインUI用と管理者用の2つの異なるテンプレートを維持する必要があります。

テンプレートのディレクトリを一般に有効にする

まず、ハックされた管理者テンプレートをベースディレクトリに格納する場所をDjangoに伝える必要があります。

そのためには、myproject/settings.pyを編集する必要があります。まず、TEMPLATES定数とこのDIRSキーを探します:

'DIRS': [],

そのコードを以下のように変更します:

'DIRS': [os.path.join(BASE_DIR, 'templates')],

Adminテンプレートをラップする(admin/baseハック)

もし単に見た目の変更を行いたいだけで、例えばカスタムスタイルシートをアドミンに渡したり、ヘッダーを削除または置換したいだけなら、admin/base_siteテンプレートを編集するだけでこのステップを完全にスキップすることができます。しかし、アドミンセクションを完全に「ラップ」したい場合、つまりメインサイト内に含まれているかのようにして、共通のヘッダーとフッターを持つ可能性がある場合は、続けて読んでください。

Djangoのadmin/base.htmltemplates/admin/base.htmlのテンプレートディレクトリにコピーする必要があります。そうすることで、ラッパーを配置できます。

containerセクションの周りのコードを編集します。これが次のようになります:

<!-- Container -->
<div id="container">
(...)
</div>
<!-- END Container -->

これが次のようになります:

{% block bodyheader %}{% endblock %}

<!-- Container -->
<div id="container">
(...)
</div>
<!-- END Container -->

{% block bodyfooter %}{% endblock %}

そして、それだけです!私たちは単にbodyheaderbodyfooterブロックタグを作成しました。そうすることで、次のステップでアドミンをラップするコードを注入できます。

カスタムアドミンテンプレートをコーディングする(admin/base_siteハック)

それから、実際のテンプレートをtemplates/admin/base_site.htmlでコーディングします(プロジェクトのルートにディレクトリを作成する必要があります):

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

{% block title %}Django with Bootstrap | Admin site{% endblock %}

{% block branding %}{% endblock %}
{% block breadcrumbs %}{% endblock %}

{% block bodyclass %}bg-light{% endblock %}

{% block extrastyle %}
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <style>
      #header, .breadcrumbs { display: none; }

      /* 管理者とのBootstrapの問題 */
      * { box-sizing: unset; }
      div.module caption { caption-side: top !important; }
      .collapse { display: block !important; }
    </style>
{% endblock %}

{% block bodyheader %}
    <div class="bg-white container">

      <div class="jumbotron">
        <h1 class="display-4">Hacking the Django Admin with Bootstrap</h1>
        <p class="lead">
          The <a ref="https://docs.djangoproject.com/en/dev/ref/contrib/admin/">Django administration site</a> is great—full-featured, easy to use, secure by design, rock solid… and somewhat ugly, which can be something of a downside when you want to integrate it with the look-and-feel of the rest of the website. Let’s sort that out.
        </p>
      </div>
{% endblock %}

{% block bodyfooter %}
    </div>

    <!-- jQueryが最初、次にPopper.js、次にBootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
{% endblock %}

分解

ここで何をしているのか説明してみましょう:

  1. テンプレートエンジンに「拡張」していることを伝えるadmin/base_site.htmlテンプレート、その定義の一部を実質的にオーバーライドします。
  2. titleブロックを使用して、閲覧中の管理者ページのタイトルをカスタマイズします。
  3. brandingbreadcrumbsブロックのコンテンツを空にしますが、本当は必要ありません。
  4. bodyclassブロックを使用して、Bootstrapのbg-lightを設定します。frontendテンプレートで行ったように。
  5. extrastyleブロックを使用して、BootstrapといくつかのCSSコードを埋め込みます。
    a. さて、#header, .breadcrumbs { display: none; }は3番の再声明のようなものですが、ブランディングとパンくずリストのセクションを両方の方法で無効にできることを知っておくと便利です。
    b. 管理者でBootstrapをDjangoのCSSと重ねるときに問題が発生することがあるので、これらはいくつかの修正です。
  6. bodyheaderおよびbodyfooterブロックを使用して、管理者コンテンツをラップします。

管理者テンプレートにアクセスできるようになったので、そのスタイルシートをさらに拡張するか、メインUIと共有されたスタイルでそれ以上何もしないかが選択できます。

注意点

本質的に同じプレゼンテーションを行うために、2つの異なるテンプレート(メインUIと管理者)を維持しています。率直に言って、これは理想的ではありません。なぜなら、ソフトウェア開発の最大の原則の一つである同じことを繰り返さない(DRY)を明示的に破っているからです。

先述したように、これはDjangoの管理者がメインUIから切り離されて設計されているためです。それに問題はありませんし、ボックスの外を考えることにも問題はありません。しかし、それはほぼ同じコンテンツを持つ2つのテンプレートを使用することを余儀なくされます。

実際には、原則的には、メインUIと管理者からのナビバーおよびその他の共通要素を含むテンプレートパターンを設計し、そのシングルソースから再利用することができます。しかし、現時点では、この記事の目的には少し過剰なアプローチです。とはいえ、そのアイデアを皆さんに植え付けておきます。😉

共有ナビゲーションバーの作成

メインUIと管理者サイトがほぼ同じ外観になったので、統合をさらに進めて共通のナビゲーション体験を作り、さらにはメインメニューに直接管理者オプションを表示することもできます。

ナビバーのスニペットは次の通りです。

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <ul class="navbar-nav mr-auto">
    <li class="nav-item">
      <a
        class="nav-link text-primary"
        href="/author/"
      >
        Go to Authors
      </a>
    </li>
    <li class="nav-item">
      <a
        class="nav-link text-primary"
        href="/article/"
      >
        Go to Articles
      </a>
    </li>
    {% if user.is_authenticated %}
    <li class="nav-item dropdown">
      <a
        aria-expanded="false"
        aria-haspopup="true"
        class="font-weight-bold nav-link text-primary dropdown-toggle"
        data-toggle="dropdown"
        href="#"
        role="button"
      >
        Admin
      </a>
      <div class="dropdown-menu">
        <a class="dropdown-item" href="/admin/myapp/author/">
          Manage authors
        </a>
        <a class="dropdown-item" href="/admin/myapp/article/">
          Manage articles
        </a>
      </div>
    </li>
    {% endif %}
  </ul>
</nav>

Bootstrapのナビバーコンポーネントの詳細については、dropdown-menuセクションに注意してください。これにより、管理者メニューが表示されます。

また、{% if user.is_authenticated %} /{% endif %}条件付きチェックを行い、管理者メニューを表示するかどうかを決定します。

最後に、今回は2つの異なるメインテンプレートを維持しているため、ナビバーのHTMLコードを両方に追加する必要があることを覚えておいてください。myapp/templates/myapp/tempalte.html そして templates/admin/base_site.htmlです。

追加: 管理者ログイン画面

管理者サイトは対応済みですが、しかしまだ未解決な点があります: ログイン画面です。

このようなものを次のように変えることができます:

Source

…このようなものになります:

以下のテンプレートをtempltes/admin/login.htmlで作成することで、それに近いものを実現できます:

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

{% load i18n static %}

{% block extrastyle %}
{{ block.super }}
<style>
#header {
  background-color: transparent !important;
}
</style>
{% endblock %}

{% block branding %}
<h1>
  <span style="color: #57C5A5 !important">ActionPlanNow.com</span>
  <br />
  <small>{% block head_title %}{% endblock %}</small>
</h1>
{% endblock %}

{% block content_title %}
<p class="lead" style="font-size: larger">
A Simple Tool for Leaders, Coaches, and Counselors.
</p>
{% endblock %}

解説

ここで行っていること:

  1. {{ block.super }}タグは、extrastyleの内容を上書きしているのではなく(templates/admin/base_site.htmlテンプレートで定義したもの)、単にそれにコンテンツを追加していることをテンプレートエンジンに伝えます(詳細はテンプレート継承を参照してください)。
  2. brandingブロックは、「Django administration」ヘッダーをもっと興味深いものに変えることができます。
  3. head_titleブロックは空の定義を設定することで取り除くことができます。
  4. content_titleブロックを使用して、いくつかの追加情報を追加します。

いくつかの考慮事項

Source

Bootstrapと同様に、Django adminサイトも独自のjQueryバンドルを搭載していますが、幸いにもDjangoの開発者はこれを考慮し、ユーザーが提供するスクリプトやライブラリとの競合を避けるため、DjangoのjQueryはdjango.jQueryとして名前空間化されています。そのため、安全に独自のコピー(私たちが行ったように)を含めることができます。

メインのスタイルシートでクラス定義を過剰に使用する際は注意が必要です。それは管理者サイトにも影響を与え、予期しない方法でその機能に影響を与える可能性があります。そのような場合、Chrome DevToolsFirefox Developer Tools(特にPage Inspector)、またはSafari Developer Toolsなどのブラウザのデバッグツールで何が起こっているかを確認できます。

デモと完全なコード

ここで説明した実装は次のようになります。

プロジェクトのすべてのコードを私のGitHubリポジトリluzdealba / djangovuejsで確認できます。

まとめ

一部の人々は、Djangoの管理画面の外観を変更する必要があまりないと合理的に主張するかもしれませんが、サイト内の異なるエンドポイントをスムーズに統合することは、UXを改善するための優れた方法であるとも言えます。これにより、2つのエンドポイント間での移行がシームレスになり、管理画面のナビゲーションもより制御しやすくなります。

そして、それを行うのはそれほど難しくありません。注意すべき点は、管理画面をどのようにラップするか、そしてサードパーティ製ライブラリを独自のJavaScriptコードやスタイルシートとどのように組み合わせるかです。幸いなことに、管理画面に、メインサイトの残りの部分に、またはその両方に簡単に統合できます。

どのようにDjangoをさらにカスタマイズできるかのアイデアが浮かぶことを願っています!

Djangoの管理画面を使って遊ぶためだけにWebアプリを構築する口実が必要な場合は、DjangoとVue.jsでWebアプリをプロトタイプ化する方法に関する先週のチュートリアルをチェックしてください。とても楽しいです。Djangoのスキルをさらに磨きたい場合は、SitePoint Premiumライブラリにたくさんのリソースがあります。

BootstrapでDjango Adminをカスタマイズする際のよくある質問(FAQ)

BootstrapでDjango Adminをカスタマイズする利点は何ですか?

Django AdminをBootstrapでカスタマイズすることにはいくつかの利点があります。まず第一に、管理者インターフェースの視覚的な魅力を高め、よりユーザーフレンドリーで直感的になります。Bootstrapは、タイポグラフィ、フォーム、ボタン、その他のインターフェースコンポーネントのための様々なデザインテンプレートを提供する人気のあるフロントエンドフレームワークです。Django Adminと統合することで、これらのテンプレートを活用して、より視覚的に魅力的で機能的な管理者インターフェースを作成できます。第二に、管理者インターフェースにカスタム機能を追加できます。例えば、カスタムアクション、フィルター、フォームを追加して、管理者インターフェースの使いやすさを向上させることができます。最後に、管理者インターフェースのリアクティブを改善し、さまざまなデバイスや画面サイズでよりアクセスしやすくなります。

Django Adminにカスタムアクションを追加する方法は?

Django Adminを使用すると、選択されたオブジェクトに対して実行できるカスタムアクションを追加できます。カスタムアクションを追加するには、選択されたオブジェクトに対して目的のアクションを実行する関数を定義する必要があります。この関数は、モデル管理者、リクエスト、および選択されたオブジェクトのクエリセットの3つのパラメータを取る必要があります。この関数を定義したら、モデル管理者の’actions’属性に追加できます。これにより、アクションドロップダウンが管理者の変更リストページに表示されます。

Bootstrapを使用してDjango Adminのデザインをカスタマイズできますか?

はい、Django Adminの外観と感じをBootstrapを使用してカスタマイズできます。Bootstrapは、タイポグラフィ、フォーム、ボタン、その他のインターフェイスコンポーネントに対する様々なデザインテンプレートを提供するフロントエンドフレームワークです。Django Adminと統合することで、これらのテンプレートを活用して、より視覚的に魅力的で機能的な管理者インターフェイスを作成できます。管理者インターフェイスの色、フォント、レイアウト、その他のデザイン要素を、ブランドアイデンティティや個人的な好みに合わせてカスタマイズできます。

Django Adminにカスタムフィルターを追加する方法は?

Django Adminを使用すると、管理者変更リストページに表示されるオブジェクトをフィルタリングするために使用できるカスタムフィルターを追加できます。カスタムフィルターを追加するには、django.contrib.admin.SimpleListFilterのサブクラスを定義する必要があります。このサブクラスは、2つのメソッド(lookupsとqueryset)を定義する必要があります。lookupsメソッドは、フィルタオプションを表すタプルのリストを返すべきです。querysetメソッドは、選択されたフィルタオプションに基づいてフィルタリングされたクエリセットを返すべきです。このサブクラスを定義したら、それをモデルの管理者の`list_filter`属性に追加できます。

追加のパッケージなしでDjango AdminでBootstrapを使用できますか?

追加のパッケージなしでDjango AdminでBootstrapを使用することは可能ですが、django-admin-bootstrapのようなパッケージを使用する方が一般的には簡単で効率的です。このパッケージは、Django AdminのBootstrapベースのテーマを提供し、BootstrapをDjango Adminと統合するのを容易にします。また、レスポンシブデザインやカスタムフォームレンダリングなどの追加機能も提供し、管理者インターフェイスの使いやすさと機能性をさらに向上させることができます。

Django Adminでフォームフィールドをどのようにカスタマイズできますか?

Django Adminを使用すると、オブジェクトの作成や編集に使用されるフォームフィールドをカスタマイズできます。フォームフィールドをカスタマイズするには、モデルアドミンの‘formfield_for_dbfield’メソッドをオーバーライドする必要があります。このメソッドは、指定されたデータベースフィールドに対して使用されるフォームフィールドインスタンスを返すべきです。フォームフィールドの属性、ウィジェット、バリデーション動作をカスタマイズして、ニーズに合わせることができます。

Django Adminにカスタムビューを追加できますか?

はい、Django Adminにカスタムビューを追加できます。カスタムビューを追加するには、モデルアドミン内でビューのロジックを処理するメソッドを定義する必要があります。このメソッドはリクエストを唯一のパラメータとして受け取り、レスポンスを返すべきです。次に、このメソッドをモデルアドミンの‘get_urls’メソッドにURLパターンとして追加することで、このビューをアドミンインターフェースからアクセス可能にすることができます。

Django Adminのリスト表示をどのようにカスタマイズできますか?

Django Adminを使用すると、アドミンの変更リストページに表示されるオブジェクトのテーブルであるリスト表示をカスタマイズできます。リスト表示をカスタマイズするには、モデルアドミンの‘list_display’属性を表示したいフィールド名のリストに設定します。また、このリストにメソッド名を含めることもでき、それにより各オブジェクトに対して対応するメソッドが呼び出され、結果が表示されます。

複雑なデータベースモデルにDjango Adminを使用できますか?

はい、Django Adminは複雑なデータベースモデルを扱うように設計されています。関連オブジェクトのインライン編集、カスタムフォームフィールド、カスタムアクションなど、複雑なデータ構造を管理するためのさまざまな機能を提供しています。ただし、非常に複雑なデータ構造や高度なデータベース操作の場合は、カスタムビュー、フォーム、アクションでDjango Adminを拡張する必要があるかもしれません。

Django Adminのパフォーマンスをどのように改善できますか?

Django Adminのパフォーマンスを改善する方法はいくつかあります。1つの方法は、データベースクエリを最適化することです。Django Adminは、モデル定義と管理オプションに基づいて自動的にデータベースクエリを生成します。ただし、これらのクエリは、特に複雑なデータ構造や大きなデータセットの場合、時に非効率的です。管理オプションをカスタマイズし、Djangoのデータベース最適化機能を使用することで、データベースクエリの数を大幅に削減し、管理インターフェイスのパフォーマンスを向上させることができます。もう1つの方法は、キャッシングを使用することです。Djangoは、高価な操作の結果や頻繁にアクセスされるデータのキャッシュに使用できる堅牢なキャッシングフレームワークを提供しています。キャッシングを使用することで、データベースの負荷を軽減し、管理インターフェイスの応答性を向上させることができます。

Source:
https://www.sitepoint.com/how-to-hack-redesign-customize-the-django-admin-with-bootstrap/