django_datatables_viewで1ページ100件超えが表示できない不具合の対処法
はじめに
Django で datatables のサーバー連携を使用できる django_datatables_view で、1 ページあたり 100 件を超えるレコードがすべて表示できない不具合の対処法を紹介します。とてもわかりにくい不具合になっており、目視だと気が付かない可能性があります。
django_datatables_view について
django_datatables_view とは、datatables のサーバー連携を使用できる Django のクラスベースビューです。
datatables とは絞り込み・ソートなど多機能なテーブルをかんたんに実装できる jQuery プラグインです。
datatables とは絞り込み・ソートなど多機能なテーブルをかんたんに実装できる jQuery プラグインです。
Django の管理画面よりもカスタマイズ豊富な上に、ほとんどプログラムを書くことなく、(デザイン, フロントエンド, バックエンドも)何も考えずにデータベース内容を一覧に表示できます。

今回のユースケースでは、下記のプログラムをお借りしました。ありがとうございます。
okoppe8/django-datatables-view-sample - GitHub
https://github.com/okoppe8/django-datatables-view-sample
1 ページあたり 100 件超えにするとレコード数がおかしい
datatables の lengthMenu を変更すると、1 ページあたりの表示件数を柔軟に変更できます。
10 件でも、1 件でも、2^53-1 件でも設定できます。

lengthMenu - datatables
https://datatables.net/reference/option/lengthMenu
ある案件で、最大「500 件」の選択ができるように設定していました。500 件にすると下記のようになります。

一見すると、正しく表示できていそうに見えますが、皆さん、このスクショにある「不具合」を1点見つけてくださいませ。
いくら北海道がデカいとはいえ、地方自治体が 500 もあるわけがないのです。(ちなみに 179 あるらしいです)
試しに次のページに行ってみましょう。

群馬県に突入しています。つまり、「1 ~ 500 件表示」となっていながら、500 件のレコードが表示できていないのです。実際には 100 件しか表示されていません。
その案件ではデフォルトは 100 件にしており、テストもそれで通っていたので目視でしか確認しておらず発見できていませんでした。気づきにくい重大な不具合を生んでしまったのです。
django_datatables_view の返却レコード数上限
django_datatables_view には返却レコード数上限の設定( max_display_length )があります。README.md には下記の記述があります。
set max limit of records returned, this is used to protect our site if someone tries to attack our site
and make it return huge amount of data max_display_length = 500
django-datatables-view · PyPI
https://pypi.org/project/django-datatables-view/
リクエスト自体は単純な GET のため、やろうと思えば大量のデータを取得する攻撃ができてしまう意図から設定されている設定です。こちらのデフォルト値は 100 になっています。
返却レコード数上限を変更する
正常に動作させるためには返却レコード数上限を変更する必要があります。lengthMenu の最大値を設定しましょう。
from django_datatables_view.base_datatable_view import BaseDatatableView
class ExampleList(BaseDatatableView):
model = MyModel
columns = ['id', 'name', 'dateAt', 'updatedAt']
max_display_length = 500
再度実行してみましょう。

無事群馬県までの 500 件が表示されるようになりました。
基本設定のクラス化
複数のページで使用している場合、設定漏れがあると不具合の原因となるので、基本設定は基底クラス化してしまいましょう。下記のように作ります。
from django_datatables_view.base_datatable_view import BaseDatatableView
class ExtendDatatableView(BaseDatatableView):
# フロントdatatablesのlengthMenu最大値と揃えること
max_display_length = 500
from app.library.extend_datatable_view import ExtendDatatableView
class ExampleList(ExtendDatatableView):
model = MyModel
columns = ['id', 'name', 'dateAt', 'updatedAt']
まとめ(反省)
- ライブラリの README はちゃんと読もう
- 目視で不具合に気がつけるようにテストデータは分かりやすくしよう
- テストは条件変更した場合の挙動も確認しよう