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

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の実装もあるようなので、いずれパッケージになるかもしれませ

Hyper-V Server2019にワークグループ環境下でWindows10(1809)から接続

Hyper-V server 2019に、ワークグループ環境にてWindows10(1809)から接続してみました。Windows10にHyper-V管理ツールがインストールされていることと、Hyper-V Serverをインストール済であることが前提です。以下、Hyper-V serverは名前がHyperVSV、アドレスは192.168.1.110としています。 まず、Hyper-V server上で、powershellを起動し、以下のコマンドを入力します。 Enable-WSManCredSSP -Role Server -Force 続いて、クライアントのWindows10のpowershell で以下のコマンドを入力します。 winrm quickconfig -Force Enable-WSManCredSSP -Role Client -DelegateComputer * -Force さらに、クライアントマシンで、gpedit(グループポリシーエディタ)を起動し、以下の要領でポリシーを設定します。 a. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLMのみのサーバー認証で新しい資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「WSMAN/*」を追加 b. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLM のみのサーバー認証で保存された資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「*」を追加 また、名前解決できるように、(notepadを管理者権限で実行し)C:\Windows\System32\Drivers\etc\hostsにサーバ名とIPアドレスの対を追加。 192.168.1.110 HyperVSV 最後に、Hyper-Vマネージャーを起動し、Windows10からHyper-V サーバに接続します。手順は以下の通りです。 「サーバーに接続」->コンピュータの選択->別のコンピューターに[HyperVSV]と入力し、[別のユーザーとして接続する

フレッツ光クロス: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-