"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

プルダウンリスト(Select)とマルチセレクトボックス。初期化と値の受取など。/Django3.0+Bootstrap4

django2.0のFieldについて、毎回、調べ直すのは面倒なので、自分用を兼ねて、サンプルを書いておきます。

今回は「Select」。

環境は Windows + anaconda です。

f:id:arakan_no_boku:20190320212948j:plain

 

ChoiceFieldと MultipleChoiceField

 

選択肢を表示して、そこから選ぶ・・というだけのことではあります。

その表示と選択のパターンは以下の4つ。

  1. 固定の選択肢を表示(静的)して、単一選択のみが可能
  2. 固定の選択肢を表示(静的)して、複数選択が可能
  3. 動的に生成した選択肢を表示して、単一選択のみが可能
  4. 動的に生成した選択肢を表示して、複数選択が可能

実際に使うのは、ほとんど「3」か「4」だと思います。

DBやファイルから選択肢を取得して、選択肢を生成するパターンですね。

Djangoだと、ModelChoiceFieldを使った例が多いですが、今回は使いません。

最近は、依存関係を疎にするため、画面(View)からDBに直接アクセスしないルールでやる時もあるので、DBあるなしでFieldを使い分けるメリットを感じないからです。

その前提で・・で。

とりあえず、上記4パターンのサンプルです。

 

forms.pyのサンプル

 

上記の4つのパターン別です。

 

固定の選択肢を表示(静的)して、単一選択のみが可能

 

     labels = ['静的単一選択','静的複数選択','動的単一選択','動的複数選択']
     CHOICE = [
          ('1','選択肢<1>'),
          ('2','選択肢<2>'),
          ('3','選択肢<3>')]
     
     one = forms.ChoiceField(
          label=labels[0],
          required=True,
          disabled=False,
          initial=['2'],
          choices=CHOICE,
          widget=forms.Select(attrs={
               'id': 'one',}))

選択肢「choices」に渡すのは、(キー,バリュー)の組合せのタプルのリストです。

上記だと「CHOICE」です。

初期表示時に選択済「selected」にするキーは「initial」に渡します。

こちらはlist。

上記の例なら、初期表示時に「 ('2','選択肢<2>')」が選択済になるというわけです。

 

固定の選択肢を表示(静的)して、複数選択が可能
     labels = ['静的単一選択','静的複数選択','動的単一選択','動的複数選択']
     CHOICE = [
          ('1','選択肢<1>'),
          ('2','選択肢<2>'),
          ('3','選択肢<3>')]
     
     two = forms.MultipleChoiceField(
          label=labels[1],
          required=True,
          disabled=False,
          initial=['2'],
          choices=CHOICE,
          widget=forms. SelectMultiple(attrs={
               'id': 'two',}))

MultipleChoiceFieldとSelectMultipleが違うだけで方法は前のサンプルと同じです。 

 

動的に生成した選択肢を表示して、単一選択のみが可能

 

このパターンは、views.pyで動的に、「choices 」と「initial」をセットします。

     labels = ['静的単一選択','静的複数選択','動的単一選択','動的複数選択']
     three = forms.ChoiceField(
          label=labels[2],
          required=True,
          disabled=False,
          widget=forms.Select(attrs={
               'id': 'three',}))    

なので、forms.pyの定義で「choices 」と「initial」は指定しません。 

 

動的に生成した選択肢を表示して、複数選択が可能 

 

このパターンも、views.pyで動的に、「choices 」と「initial」をセットします。 

     labels = ['静的単一選択','静的複数選択','動的単一選択','動的複数選択']
     four = forms.MultipleChoiceField(
          label=labels[3],
          required=True,
          disabled=False,
          widget=forms. SelectMultiple(attrs={
               'id': 'four',}))
   

forms.pyの定義で、これも、「choices 」と「initial」は指定しません。

 

views.pyにおける動的選択肢セット

 

forms.pyの中で選択肢をセットする場合は、views.pyの中で特にすることはないのですけど、上記の後の2つのように「choices」と「initial」を指定していない場合は、views.pyでセットする必要があります。

 

単一選択の場合
        form = forms.SmplForm()
        choice1 = []
        choice1.append(('1','選択肢(1)'))
        choice1.append(('2','選択肢(2)'))
        choice1.append(('3','選択肢(3)'))
        choice1.append(('4','選択肢(4)'))
        form.fields['three'].choices = choice1
        form.fields['three'].initial = ['3']

単純にタプルのリストを生成して、choicesにセットし、キー値をひとつだけ収めたlistを生成して、initialにセットする 。

ただ、それだけです。

DBからデータを取得した場合は、Selectした値をタプルにして、listに追加してやれば同じようにできると考えれば、まあ、わかりやすいです。

ただ、form内のフィールドを取得する方法が、意外と情報がないので、忘れてしまうと、ちょっとてこずりますけどね。

 

複数選択の場合
     form = forms.SmplForm()
     choice1 = []
     choice1.append(('1','選択肢(1)'))
     choice1.append(('2','選択肢(2)'))
     choice1.append(('3','選択肢(3)'))
     choice1.append(('4','選択肢(4)'))
     form.fields['four'].choices = choice1
     form.fields['four'].initial = ['1','2','3','4']   

複数選択の場合もchoicesは同じです。

ただ、複数選択の場合は、初期表示時に複数が「selected」になる場合があるので、initialに渡すリストに値が複数はいる場合があるくらいです。

ちなみに。

上記の例だと、初期表示時は全選択になります。

 

views.pyでの選択値の受け取り方

 

Submitボタンを押して、request.POSTで選択肢を受け取る想定です。

 

単一選択の値を受け取る

 

例えば、forms.pyで「one」という名前で定義したFieldで選択した値は

request.POST["one"] 

で受け取ります。

 

複数選択の値を受け取る

 

でも。

上記だと、複数選択した場合でも最後のひとつしか受け取れません。

なので、複数選択する可能性のあるFieldの値は

 request.POST.getlist("two")

のように、POST.getlist()をつかって取得します。

いちおう、こんなもんですかね。

最後に、サンプルのソース全体と実行した時の画面イメージをのせておきます。

 

サンプルのソース全体

 

サンプルなので、上記の4つのパターンをひとつの画面にまとめてます。

それで、選択された値を単純に表示するだけの処理です。

 

まずforms.py
from django import forms

class SmplForm(forms.Form):
     labels = ['静的単一選択','静的複数選択','動的単一選択','動的複数選択']
     CHOICE = [
          ('1','選択肢<1>'),
          ('2','選択肢<2>'),
          ('3','選択肢<3>')]
     
     one = forms.ChoiceField(
          label=labels[0],
          required=True,
          disabled=False,
          initial=['2'],
          choices=CHOICE,
          widget=forms.Select(attrs={
               'id': 'one',}))
     
     two = forms.MultipleChoiceField(
          label=labels[1],
          required=True,
          disabled=False,
          initial=['2'],
          choices=CHOICE,
          widget=forms. SelectMultiple(attrs={
               'id': 'two',}))

     three = forms.ChoiceField(
          label=labels[2],
          required=True,
          disabled=False,
          widget=forms.Select(attrs={
               'id': 'three',}))

     four = forms.MultipleChoiceField(
          label=labels[3],
          required=True,
          disabled=False,
          widget=forms. SelectMultiple(attrs={
               'id': 'four',}))

-- 

次はviews.py
from django.http.response import HttpResponse
from django.shortcuts import render, render_to_response
from django.contrib.staticfiles.templatetags.staticfiles import static
from . import forms
from django.template.context_processors import csrf

def demo2(request):
    # 入力結果を格納する辞書
    results = {}
    ret = ''
    if request.method == 'POST':
        # 入力されたデータの受取
        results['one'] = request.POST["one"]
        results['two'] = request.POST.getlist("two")
        results['three'] = request.POST["three"]
        listret = request.POST.getlist("four")
        print(listret)
        ret = 'OK'
        c = {'results': results,'ret':ret,'listret':listret}
    else:    
        form = forms.SmplForm()
        choice1 = []
        choice1.append(('1','選択肢(1)'))
        choice1.append(('2','選択肢(2)'))
        choice1.append(('3','選択肢(3)'))
        choice1.append(('4','選択肢(4)'))
        form.fields['three'].choices = choice1
        form.fields['three'].initial = ['3']
        form.fields['four'].choices = choice1
        form.fields['four'].initial = ['1','2','3','4']    
        c = {'form': form,}
        # CFRF対策(必須)
        c.update(csrf(request))
    return render(request,'demo03.html',c)

-- 

表示用HTML
{% extends 'base.html' %}
{% load static %}
{% load bootstrap4 %}
{% load widget_tweaks %}

{% block header %}
<link rel="stylesheet" href="{% static "css/dj_talk.css" %}"></link>
{% endblock %}

{% block title %}
  CharFieldのサンプルいろいろ
{% endblock %}

{% block content %}
<div class="container bg-light">
    <form action="" method="post">{% csrf_token %}
        <h1>ビルトインフォームサンプル</h1>
        {% if ret %}
        	{% for key,val in results.items %}
        	<div class="form-group row my-4">  
            	<label class="col-lg-3 col-form-label">
            		<h4>{{ key }}</h4>
            	</label>
       			<div class="col-lg-6">       
	            	<h4>{{ val }}</h4>
    			</div>
    		</div>        	
        	{% endfor %}
        	<div class="form-group row my-4">  
            	<label class="col-lg-3 col-form-label">
            		<h4>動的複数選択</h4>
            	</label>
       			
       			<div class="col-lg-6">       
	            	<h4>
	            	{% for v in listret %}
	            		{{ v }}
	            	{% endfor %}
	            	</h4>
    			</div>
    		</div>        	
        {% else %}
        	{% for key,val in errors.items %}
        		<h2>{{ key }} : {{ val }}</h2>
        	{% endfor %}
        	{% for field in form %}
        	<div class="form-group row my-4">  
            	<label class="col-lg-3 col-form-label">
            		<h4>{{ field.label_tag }}</h4>
            	</label>
       			<div class="col-lg-6">       
	            	{{ field|add_class:"form-control font-weight-bold" }}
    			</div>
    		</div>
			{% endfor %}
		   	<div class="form-group row my-4">	
    			<div class="col-lg-3">       
	        	    <button type="submit" class="btn btn-primary">送信する</button>
    			</div>
        	</div>
         {% endif %}
     </form>
</div>  
{% endblock %}

複数選択の場合の値の違いがわかるように、普通に表示する場合と{% for を使って、表示する場合の2通りをやってます。

 

今回の記事の前提

 

django、bootstrapのインストールや利用設定、および、djangoで入力画面を作る部分は、以下の記事の内容を前提にしています。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

 

実行した画面

 

実行はrunserverを使います。

 

 

初期表示

 

f:id:arakan_no_boku:20190210235951j:plain

ここで、静的複数選択で「選択肢<3>」も選んで、「送信する」ボタンを押した結果がこちらです。

f:id:arakan_no_boku:20190211000058j:plain

twoのところで、getlistしたものをそのまま表示してます。

まあ、実際のところ、こんな風にキーだけ表示することはないですけど、HTML上で選択値を取得するサンプルということで・・。

ではでは。