スキップしてメイン コンテンツに移動

Djangoで多段かつ複数チェックボックスにて絞り込みをおこなう

今回もタイトル通りですが、ネットで検索しても多段・複数チェックボックスを用いての例がほとんどみつかりませんでした。チェックボックスについては一段の例はあったのですが、やってみたところ、簡易的に多段かつ複数の絞り込みができたので、備忘録として挙げてみました。

早速ですが以下models.pyです。
class mb_basic_spec(models.Model):
    class Meta:
        managed = False
        db_table = 'mb_basic_spec'

    art_id = models.BigIntegerField(primary_key=True, db_column='art_id')
    art_name = models.TextField()
    chipset_vendor = models.CharField(max_length=128)
    chipset = models.CharField(max_length=128)
    vendor = models.CharField(max_length=128)
    cpu_socket = models.CharField(max_length=128)
    form_factor = models.CharField(max_length=128)
    memory_form = models.CharField(max_length=128)
    memory_type = models.CharField(max_length=128)
    
class v_vendor(models.Model):
    class Meta:
        managed = False
        db_table = 'view_vendor'

    vendor_id = models.IntegerField(primary_key=True, db_column='vendor_id')
    vendor = models.CharField(max_length=128)

class v_chipset(models.Model):
    class Meta:
        managed = False
        db_table = 'view_chipset'

    chipset_id = models.IntegerField(primary_key=True, db_column='chipset_id')
    chipset_vendor = models.CharField(max_length=128)
    chipset = models.CharField(max_length=128)
実は上記はすべてviewですが、managed=Falseとすることでpython manage.py migrateしてもデータベースに変更は入りませんので手動でviewをメンテする必要がありますが、今回はそれには触れません。
つづいて、views.pyです。
...
from .models import mb_basic_spec, v_vendor, v_chipset

class mb_basic_specListView(ListView):
    model = mb_basic_spec
    template_name = 'myapp/mb_basic_spec_list.html'

    def get_context_data(self, **kwargs):
        context = super(mb_basic_specListView, self).get_context_data(**kwargs)

        vendors = v_vendor.objects.all()
        chipsets = v_chipset.objects.all()

        context['vendors'] = vendors
        context['chipsets'] = chipsets

        return context

    def get_queryset(self):
        results = mb_basic_spec.objects.all()
        q_vendors = self.request.GET.getlist('vendor', None)
        q_chipsets = self.request.GET.getlist('chipset', None)

        if len(q_vendors) != 0:
            results = results.filter(vendor__in=q_vendors)

        if len(q_chipsets) != 0:
            results = results.filter(chipset__in=q_chipsets)

        return results
 
get_context_dataでは、contextにvendorsとchipsetsをそれぞれセットしておきます。そうしないとcheckboxが表示されません。また、get_querysetでも、それぞれ self.request.GET.getlistにて絞り込みするようにしておきます。絞り込みは記述通り resultsを上書きすることで多段絞り込み出来るようにしています。
さらに今回は、チェックボックスの状態を保持させたいので、カスタムテンプレートフィルタを作成します。まず、フォルダーを作成しその中に、空の__init__.pyも作成しておきます。
mkdir myapp/templatetags
touch myapp/templatetags/__init__.py
つづいてカスタムフィルターを作成します。名前は myapp/templatetags/mb_basic_spec_list_filters.py としてみました。
from django import template

register = template.Library()

@register.filter
def vendor_checked(value, querydict):
    vendors = querydict.getlist('vendor')
    if str(value) in vendors:
        return "checked"
    return ""

@register.filter
def chipset_checked(value, querydict):
    chipsets = querydict.getlist('chipset')
    if str(value) in chipsets:
        return "checked"
    return ""
つづいてtemplateを作成します。名称はmb_basic_spec_list.htmlとしました。
{% extends "base/base.html" %}
{% load mb_basic_spec_list_filters %}
{% block content %}
<form method="get" action="" name="myapp_filter">
    <div>
        <span>vendor: </span>
        {% for vendor in vendors %}
            <input type="checkbox" id="filter_vendor_{{ vendor.pk }}" 
                name="vendor" 
                value="{{ vendor.vendor }}"
                {{ vendor.vendor | vendor_checked:request.GET }}/>
                {{ vendor.vendor}}
            </input>
        {% endfor %}
        <br/>
        <span>chiset: </span>
        {% for chipset in chipsets %}
            <input type="checkbox" id="filter_chipset_{{ chipset.pk }}" 
                name="chipset" 
                value="{{ chipset.chipset }}"
                {{ chipset.chipset | chipset_checked:request.GET }}/>
                {{ chipset.chipset }}
            </input>
        {% endfor %}
        <br/>
        <button id="filter">絞り込み</button>
    </div>
    <table class="ui celled table" style='width:1000px;overflow-x:scroll'>
        <thead>
            <tr>
                <th>name</th>
                <th>chipset vendor</th>
                <th>chipset</th>
                <th>vendor</th>
                <th>cpu socket</th>
                <th>form factor</th>
                <th>memory form</th>
                <th>memory type</th>
            </tr>
        </thead>
        <tbody>
            {% for prop in mb_basic_spec_list %}
            <tr>
                    <td>{{ prop.art_name }}</td>
                    <td>{{ prop.chipset_vendor }}</td>
                    <td>{{ prop.chipset }}</td>
                    <td>{{ prop.vendor }}</td>
                    <td>{{ prop.cpu_socket }}</td>
                    <td>{{ prop.form_factor }}</td>
                    <td>{{ prop.memory_form }}</td>
                    <td>{{ prop.memory_type }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</form>
{% endblock %}
カスタムテンプレートは2行目でロードしています。なおcssにはsemantic uiを使っています。
最後はurls.pyです。以下を追加します。
from django.urls import path, include
from . import views

app_name = 'myapp'

urlpatterns = [
...
path('plane_mb_basic_spec/', views.mb_basic_speckListView.as_view(), name='mb_basic_spec_list'),
]
今回は以上です。それでは。

コメント

このブログの人気の投稿

wsdd を使ってSamba サーバをネットワークに表示

Windows 10のアップデートで、セキュリティー対応のため、smbv1がデフォルトではインストールされなくなり、Samba serverがエクスプローラーのネットワークに表示されなくなってしまいました。そこで、いくつか方法を調べたのですが、linuxでwsdの実装がないか探したところ、 https://github.com/christgau/wsdd が、見つかりましたので、さっそくインストールしてみました。まだパッケージにはないようですが、インストール自身は簡単です。wsdd自体は以下のように取得し、linkを張っておきます。 cd /usr/local/bin/ sudo wget https://raw.githubusercontent.com/christgau/wsdd/master/src/wsdd.py sudo chmod 755 wsdd.py sudo ln -sf wsdd.py wsdd こちらのsambaサーバはDebianなので、/etc/systemd/system/wsdd.serviceは以下のようにしました。 [Unit] Description=Web Services Dynamic Discovery host daemon Requires=network-online.target After=network.target network-online.target multi-user.target [Service] Type=simple ExecStart=/usr/local/bin/wsdd -d MYDOMAIN [Install] WantedBy=multi-user.target wsdd -d MYDOMAINのところを、環境にあわせて書き換えてください。 次に、systemdに登録・起動テストを行います。 systemctl enable wsdd systemctl start wsdd 起動に成功すると、エクスプローラーのネットワークに表示されます。  なおこのwsddはpython3が必要です。一度試してみてください。SMBv1/CIFSを停止していても、大丈夫です。 cで書かれたほかのwsddの実装もあるようなので、いずれパッケージになるかも...

Windows デバイス暗号化 のサポートで "許可されていない dma 対応バス/デバイスが検出されました"の対処

Windows でセキュリティー関係を見ているのですが、とあるPCでmsinfo32で確認すると"デバイス暗号化のサポート"で"許可されていない dma 対応バス/デバイスが検出されました"と出ていました。このPCの場合、それ以外はOK(なにも表示されない)だったのですが、ネットでしらべるとMSのドキュメントではハードウェアベンダーに問い合わせるなどと敷居が高く具体的にどこが引っかかっているかわかりません。そこでほかに方法はないかとしらべやってみたところ、"前提条件をみたしています"まで持って行けたので、本稿を挙げた次第です。 具体的には、以下のようにします。 1-a. 許可するDMA対応バス・デバイスを指定するレジストリの所有権と書き込み設定をおこなう。 以下のレジストリキーの所有者を自分自身(管理ユーザ)のものにし、フルコントロール権を付与する。 HKLM\SYSTEM\CurrentControlSet\Control\DmaSecurity\AllowedBuses もしくは 1-b. MicrosoftよりPsExecをダウンロードし、System権限でRegeditを立ち上げ編集する。 Microsoftより、https://docs.microsoft.com/en-us/sysinternals/downloads/psexec にある こちら をダウンロードし、解凍する。解凍すると、x64の場合、PsExec64.exeがあるので、管理者権限で以下を実行し、システム権限でregeditを立ち上げることが出来るようになる。 cd Downloads\PSTools .\PsExec64.exe -sid C:\Windows\regedit.exe 2-a. パワーシェルスクリプトを実行し、PnPデバイスのうちインスタンスがPCIで始まるものを"AllowedBuses"に追加する。 以下のパワーシェルスクリプトを作成する。たとえばDocuments\allow-dma-bus-device.ps1として作成する。( こちらの記事のものを使用させていただきました: Thank you! ) $tmpfile = "$($env:T...

フレッツ光クロス:MAP-E ROUTER by Debian Box (iptables)

フレッツ光クロスがようやく開通したので、Debianにてrouterを構成し接続してみました。なお、プロバイダーを選ぶにあたっては、IPoE方式がそれぞれ異なるため検討したところ、IPoEでは、MAP-Eでもv6plusとocnバーチャルコネクトがあり、前者がポート数240なのに対し、後者は約4倍のポート数が使えるようなネットの情報をみて、OCNバーチャルコネクトを選択しました。(プロバイダーとしてはぷららです。なおDS-LiteはCE側でのNATではないので今回は見送りました。)そこで、OCN バーチャルコネクトをDebian(iptables)で実現するとどうなるかと思い、ネットの情報を頼りにしつつ、設定した次第です。 実際に試した結果、とりあえず通信できていますが、MAP-Eは本来マッピングルールをマップサーバから取得するはずなので、今回のやり方が正解とはいえませんし、仕様変更されると通信できなくなる可能性があります。あくまでも参考程度ですが、本稿をUPしてみました。 2023/03/16追記: こちら にゲームコンソールNAT越え(Nintendo Switch ナットタイプ A判定)対応版を投稿しました。 2023/03/28追記:※1の記述および3行無効化によりNAT越え(Nintendo Switch ナットタイプ B判定)できるようになりました。 構成は以下の通りです。 ルーターがDebianで回線がOCNバーチャルコネクトであること以外はなにも特別なところはない構成です。 さて、いきなり設定ですが、まず、割り当てられたプレフィックスを確認します。 確認は、 dhclient -6 -d -P enp2s0 とします。出力の中に 前略 RCV: | | X-- IAPREFIX 2400:4050:5c71:af00::/56 後略 このようにプレフィックスが表示されるので、その確認したプレフィックスを書き留めておきます。これを こちらで 入力します。すると、 CE: 2400:4050:5c71:af00:99:f171:c600:2f00 IPv4 アドレス: 153.241.113.198 ポート番号:(1776-1791 2800-2815 3824-3839) 4848-4863 5872-5887 6896-...