ちゃぱブログ / エンジニアリング / マネジメント

とあるプロダクトの運用組織のマネジメントしてる人の雑記。主にエンジニアリングやマネジメントのことを書きます。ときおりプチ情報も

データがたまっても平気な高機能な一覧をData Tables&Djangoで開発(Ajax利用)

概要

一覧の検索やソート、ページングなどを自分で実装するのはなかなかに骨が折れます。いくつかの便利なライブラリがあり、そのひとつであるData TablesをDjangoで使う実装例を紹介します。

ただ、そのまま実装するとデータ量が多くなったときにJavascript側での動作が重くなってしまいます。なので、本記事ではajaxを使ってデータ量が多くなっても対応できるように実装しました。

この記事は、Data Tablesでどのようなことができるのかを詳しく解説するものではなく、まずは動くものができるところまでを体感してもらうことを優先しています。

完成系のイメージはこのような感じです。

f:id:as_chapa:20200828174614p:plain
Data Tables完成イメージ

完成系のソースはこちらに置いてあります。 github.com tag:v1.0

イチから作る場合の手順

前半はほぼほぼDjangoの話になってしまいます。

DjangoとData Tables関連ライブラリのインストール

まずはDjangoとData Tablesを利用するためのライブラリをインストールします。

$ pip install django==2.2
$ pip install django-datatables-view==1.19.1

※バージョンは多少変わっても動くと思います

Djangoの初期設定&アプリ作成

次にアプリケーションを作ります。

$ django-admin startproject config .
$ django-admin startapp sample

このままだとsampleが動いてくれないので、 settings.py のINSTALLED_APPSにsampleを追加します。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample' # ←これを追記
]

データベース作成

お次は一覧に表示するためのDBを格納するために、簡単なModelを作るために models.py を変更します。

from django.db import models

# Create your models here.
class Book(models.Model):
    """本"""
    class Meta:
        db_table = 'book'
    
    title = models.CharField(verbose_name="本のタイトル", max_length=255)
    author = models.CharField(verbose_name="著者", max_length=255)

本のタイトルと著者名を登録するためだけの簡単なテーブルです。

models.py ができあがったところで、マイグレートします。今回はData Tablesを試してみることが目的なので、DBはSQLiteとします。(DjangoはデフォルトでSQLiteが指定されるので、特に気にすることはないです)

$ python manage.py makemigrations
$ python manage.py migrate

ついでにテスト用のデータも投入します。

$ python manage.py shell < sample/create_testdata.py

URLディスパッチャ作成

まずは、 config/urls.py にsampleへのディスパッチ行を追加します。

urlpatterns = [
    path('admin/', admin.site.urls),
    path('sample/', include('sample.urls')) # ←ここを追加
]

続いてアプリの配下にurls.pyを作成します。

from django.urls import path

from . import views

app_name = 'sample'
urlpatterns = [
    path('booklist/', views.BookList.as_view(), name='booklist'),
    path('booklist_ajax/', views.BookJsonView.as_view(), name='booklist_ajax'),
]

ここで、Data Tablesで呼び出すDjango側のエンドポイントを指定しておきます。今回の例では booklist_ajax としました。

ビューの作成

ビューを作ります。 django-datatables-view を利用しているので、ajaxのエンドポイント部分はとてもシンプルにできています。

from django.views import generic
from django.views.generic import ListView
from django_datatables_view.base_datatable_view import BaseDatatableView

from .models import Book

class BookList(ListView):
    model = Book
    template_name = 'sample/book_list.html'

class BookJsonView(BaseDatatableView):
    # モデルの指定
    model = Book
    # 表示するフィールドの指定
    columns = ['id', 'title', 'author']

    # 検索方法の指定:部分一致
    def get_filter_method(self):
        return super().FILTER_ICONTAINS

BookList は一覧全体を表示するためのもので、特段捻りもなくクラスビューで構築しました(これはListViewじゃなくても良かった気がします)。 BookJsonView がData Tables用になります。対象のテーブルを、 model で指定し、その中から一覧で表示したい項目を columns で指定します。 FILTER_ICONTAINS はマストではないのですが、部分一致で検索するために追加しています。

やっと見た目のところに到達・・・

色々とbase.htmlを作ったりとしているのですが、肝となる記述は、 template/sample/book_list.html の以下の箇所です。

<div class="container">
    <table id="datatable" class="table table-striped table-bordered table-hover dataTable no-footer dtr-inline">
        <thead>
            <tr>
                <th>No.</th>
                <th>本名</th>
                <th>著者名</th>
            </tr>
        </thead>
    </table>
</div>

ここは、Data TablesのJavascriptでテーブルを完成させるための箇所です。ヘッダーだけ書いておきます。ここで注意しなくてはいけないのが、<th></th> の数が、views.pyのcolumnsで選択した数と一致することです。 あとは、ajax部分を以下のように書けば勝手にajax向けのエンドポイントにリクエストを投げて、返却されたjsonをいい感じにJavascriptで処理してくれます。 (ほんと便利)

<script>
$(document).ready(function() {
    var oTable = $('#datatable').dataTable({
        // ...
        "processing": true,
        "serverSide": true,
        "ajax": "{% url 'sample:booklist_ajax' %}" // 上で作成したエンドポイント
    });
    // ...
});
</script>

地味なノウハウとして、今回Bootstrap4を使っているのですが、Bootstrap4のオフィシャルページで指定されるjQueryは「slim」というバージョンで、これだとajaxが動かないです。ですので、 base.html の以下のところをslimじゃないものに置き換えています。

    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

さてやっと動かす日がきた・・・

ここまででおそらく動くようになったはずなので、

$ python manage.py runserver

として、エラーが出ないことを確認したら、 http://127.0.0.1:8000/sample/booklist/ にアクセスしてみてください。 冒頭に張り付けたキャプチャのような画面が表示されるはずです。

さいごに

これだけ高機能のものを自作で作ろうとするととても大変です。数日前に、ページングの実装をしようとして萎えていたので、試してみて実際に動いたときは感動しました。 見た目など融通が効かないところがありそうだなとは思うので、そこはもう少し調べていきたいと思います。

参考

おまけ

Templateの書き方や、startproject時のプロジェクト名などは、以下の書籍を参考にさせていただきました。とても勉強になる良書過ぎてDjango初心者の身分としては大変助かる書籍です。 www.amazon.co.jp