前提・実現したいこと
djangoを使用し、htmlのテーブルでデータを表示し、ページング、ソート、検索機能を実装したいです。
現在ページングと検索機能を実装したが、追加でソート機能を実装する段階で詰みました。
イメージとしてはテーブルのヘッターを複数回クリックすることで昇順、降順、元もソート順で切り替えることを実現したいです。
発生している問題
JSのライブラリだと単一ページのソートしかできないので、すべてのデータのソートを実現するために一回django側に返す必要があると感じました。
しかし返す方法として、今テーブルのヘッターにリンクをつけてrequest.getでキーワードのソート項目を受け取ろうとしていますが、複数回クリックで切替の機能の実現方法が思いつかないです。
該当のソースコード
view.py
def system_list(request): # キーワード&プルダウンリストの値をとってくる # クエリがnullの場合ページ遷移でエラーが出るので空文字を入れる if request.GET.get('project_name'): q_project_name = request.GET.get('project_name') else : q_project_name = "" if request.GET.get('system_name'): q_system_name = request.GET.get('system_name') else : q_system_name = "" if request.GET.get('lep'): q_lep = request.GET.get('lep') else : q_lep = "" if request.GET.get('lem'): q_lem = request.GET.get('lem') else : q_lem = "" q_oss_status = request.GET.getlist('oss_status') # システムテーブルにあるデータ(および関連するプロジェクトのデータ)を全て取得 systems = SystemList.objects.all() # 検索パラメータがあるかどうか if bool(request.GET): # OSSのフィルターが一つも選択されていない場合は全項目を対象とする if not q_oss_status: q_oss_status = ['1', '2', '3', '4'] # LEP,LEMを検索するために苗字と名前を半角スペースを挟み結合 queryset = systems.annotate(lep=Concat('lep_last_name', Value(' ') ,'lep_first_name'), lem=Concat('lem_last_name', Value(' ') ,'lem_first_name') ) systems = queryset.filter(project_name__icontains=q_project_name, system_name__icontains=q_system_name, lep__icontains=q_lep, lem__icontains=q_lem, oss_status__in=q_oss_status ) # 選択状態の維持のため再設定 q_oss_status = request.GET.getlist('oss_status') # 件数を取得 num = len(systems) # ページング paginator = Paginator(systems.order_by('project_name','system_name'), 20) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) context = {'paginator':paginator, 'page_obj':page_obj, 'num':num, 'q_oss_status':q_oss_status, } return render(request, 'asi/system_list.html', context)
html
<div class="right_col" role="main"> <div class="page-title"> <div class="title_left"> <h2> <i class="fas fa-clipboard-list fa-fw"></i> <span>{% trans "page.page_title.system_list" %}</span> </h2> </div> <div align="right"> <a href="/asi/system/create" type="button" class="btn btn-outline-primary btn-sm mx-1"> <i class="fas fa-plus"></i></i> {% trans "page.button.system_create" %} </a> </div> </div> <div class="nav justify-content-end"> <div class="form-group"> <!-- 検索 --> <form action="{% url 'system_list' %}" method="get"> <div class="form-inline"> <!-- セキュリティリスク対応状況検索フォーム --> <select name="oss_status" id="oss_status_multiple" multiple="multiple"> <option value=1>{% trans "page.option.open" %}</option> <option value=2>{% trans "page.option.scanning" %}</option> <option value=3>{% trans "page.option.done" %}</option> <option value=4>{% trans "page.option.suspend" %}</option> </select> <!-- クライアント/案件名 --> <div class="col-xs-2"> <input name="project_name" class="form-control custom-select-sm" value="{{ request.GET.project_name }}" placeholder="{% trans "page.label.client_project" %}" type="text"> </div> <!-- システム名検索フォーム --> <div > <input name="system_name" class="form-control custom-select-sm" value="{{ request.GET.system_name }}" placeholder="{% trans "page.label.system_name" %}" type="text"> </div> <!-- LEP検索フォーム --> <div class="col-xs-2"> <input name="lep" class="form-control custom-select-sm" value="{{ request.GET.lep }}" placeholder="LEP" type="text"> </div> <!-- LEMフォーム --> <div > <input name="lem" class="form-control custom-select-sm" value="{{ request.GET.lem }}" placeholder="LEM" type="text"> </div> <button type="submit" class="btn btn-outline-primary btn-sm mx-1">{% trans "page.button.search" %}</button> </div> </form> </div> <!-- ここまで --> <!-- <button type="button" class="btn btn-outline-primary btn-sm mx-1"><i class="fas fa-arrow-down"></i> BlackDuckデータ取込</button> --> </div> <div class="row"> <div class="form-group col-md-12"> <table class="table table-hover table-sm" style="width: 100%;"> <thead> <tr> <th>{% trans "page.label.client_project" %}</th> <th>{% trans "page.label.system_name" %}</th> <th>{% trans "page.label.oss_status" %}</th> <th>LEP</th> <th>LEM</th> <th>{% trans "page.label.last_diagnosis_date" %}</th> <th>{% trans "page.label.system_insert_date" %}</th> <th></th> </tr> </thead> <tbody> {% for row in page_obj %} <tr> <div> <td width=15%> <p id="wrap"> {{ row.project_name |default:""}} </p> </td> <td width=15%> <p id="wrap"> <a href="/asi/system/{{row.system_id}}/component">{{ row.system_name |default:""}}</a> </p> </td> <td width=15%> {{ row.get_oss_status_display |default:""}} </td> <td width=10%> <p id="wrap"> {{ row.lep_last_name |default:""}} {{ row.lep_first_name |default:""}} </p> </td> <td width=10%> <p id="wrap"> {{ row.lem_last_name |default:""}} {{ row.lem_first_name |default:""}} </p> </td> <td width=10%> {{ row.diagnosis_date|date:"Y-n-j" }} </td> <td width=12%> {{ row.insert_date|date:"Y-n-j"}} </td> <td> <a href="/asi/system/{{row.system_id}}"><i class="fas fa-external-link-alt"></i></a> </td> </div> </tr> {% endfor %} </tbody> </table> </div> </div> <!-- ページネーションと件数表示 --> <div style="float: right; margin: 0.3rem; font-weight: bold;"> {{ page_obj.start_index }} ~ {{ page_obj.end_index }} {% trans "page.pagination.items" %} / {{ page_obj.paginator.count }} {% trans "page.pagination.items" %} </div> {% include "asi/pagination.html" %} <br> {% endblock %}
多言語化タグやJSのファンクションの部分は無視していただければと思います。
試したこと
初期はlist.jsやDataTables、Tablesorterを試しましたが、単一ページでのソートしかできないのであきらめました。
django-tables2についても調べましたが、ページングと検索の部分をかなり変更する必要があるみたいなのでやめておきました。
解決法をご教示いただければ幸いです。
あなたの回答
tips
プレビュー