動的なformを作る2 - jQueryを使って複数のコンボボックスを連動させる

前提

  1. simplejsonがインストールされていること。
  2. jQueryがインストールされていること。

仕様

  1. 車名から関連した型番を取得。

model作成

まずはサンプルのmodelを作成します。

models.py

from django.db import models

class Car(models.Model):
    name = models.CharField(max_length = 20)

class Model(models.Model):
    car = models.ForeignKey(Car)
    model = models.CharField(max_length = 50)

データの入力

次にCar, Modelモデルにサンプルデータを入力します。

>>>from appname.models import Car, Model
>>>Car.objects.create(name = u'フェアレディ')
>>>Car.objects.create(name = u'レビン')

>>>car1 = Car.objects.get(pk = 1)
>>>car2 = Car.objects.get(pk = 2)

>>>Model.objects.create(car = car1, model = 'S30')
>>>Model.oblects.create(car = car1, model = 'SR311R')

>>>Model.objects.create(car = car2, model = 'TE-27')
>>>Model.objects.create(car = car2, model = 'AE-92')

formの作成

まずは、Car, Modelモデルのデータを表示できるようにします。

forms.py

from appname.models import Car, Model
from django  import forms

class AutoForm(forms.Form):
    car = forms.ModelChoiceField(queryset = Car.objects.all())
    model = forms.ModelChoiceField(queryset = Model.objects.all())

templateファイル

<table>
{{ form }}
</table>

表示してみます。

Carモデルデータ表示
related_combo01

Modelモデルデータ表示
related_combo02

連携させてみる

連携を実現するためにinputタグのhiddenのフィールドにjsonデータで格納して、
javascriptで表示を制御します。

まずは、AutoFormクラスが呼ばれるたびに、jsonデータを作成する処理を追加します。

forms.py

from appname.models import Car, Model
from django  import forms
import simplejson

class AutoForm(forms.Form):
    car = forms.ModelChoiceField(queryset = Car.objects.all())
    model = forms.ModelChoiceField(queryset = Model.objects.all())
    json = forms.CharField(max_length = 1000, widget = forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        super(AutoForm, self).__init__(*args, **kwargs)
        models = {}
        for car in Car.objects.all():
            models[car.id] = [(a.id, a.model) 
                    for a in Model.objects.filter(car = car)]
        json = simplejson.dumps(models)
        self.field['json'].widget = forms.HiddenInput(attrs = {'value': json})

HTMLソースを見てみます。

<table>
<tr><th><label for="id_car">Car:</label></th><td>
<select name="car" id="id_car">
<option value="" selected="selected">---------</option>
<option value="1">フェアレディ</option>
<option value="2">トレノ</option>
</select>
</td></tr>
<tr><th><label for="id_model">Model:</label></th><td>
<select name="model" id="id_model">
<option value="" selected="selected">---------</option>
<option value="1">S30</option>
<option value="2">SR311R</option>
<option value="3">TE-27</option>
<option value="4">AE-92</option>
</select>
<input type="hidden" name="json" 
    value="{&quot;1&quot;: [[1, &quot;S30&quot;], [2, &quot;SR311R&quot;]], 
            &quot;2&quot;: [[3, &quot;TE-27&quot;], [4, &quot;AE-92&quot;]]}" 
    id="id_json" />
</td></tr>
</table>

次に制御するjavascriptを作成します。
まず初めに、json Parser json_sans_eval.jsをダウンロードしインストールします。
さらにjfilter.jsをダウンロードしてインストールします。

そして各scriptが使えるようにtemplateファイルを修正します。

templateファイル

<script type = "text/javascript" src = "/media/js/jquery.js"></script>
<script type = "text/javascript" src = "/media/js/jfilter.js"></script>
<script type = "text/javascript" src= "/media/js/json_sans_eval.js"></script>
<script type = "text/javascript">
<!--
    $(document).ready(function(){
        jfilter({
            source: '#id_car',
            target: '#id_model',
            json: '#id_json',
        });
    })
//-->
</script>

<table>
{{ form }}
</table>

反映した結果は

related_combo03

ただし、セキュリティの関係で不適な場合があります。
サイトの性質に合わせて使用してください。

twitter 2009-08-18 01:01:14.659822

関連ページ

参照サイト

Recent Updates

URLConf Tip 01 - キャプチャの有無にかかわらず同一のviewで処理する
Markdownの入力補助"wmd"をAdmin siteで使う
ModelFormでfieldのwidgetを変更する
動的なformを作る 6 - Dynamic Inline Admin site編
Formsetsを使う3 - inlineformset_factory編
動的なformを作る 5 - django-dynamic-formset編
Formクラスからメディアを定義する
複数のmodelを結合する 2 - Proxy model編
複数のmodelを結合する 1
ModelFormでfieldの表示順番を変える
Admin siteのwidgetを個別に変更する
formfield_overridesを使ってAdmin siteのwidgetを変更する
Admin siteのlist_displayをカスタマイズする - リンク編
Admin siteのlist_displayをカスタマイズする - 基本編
Admin siteのTextareaの高さを自在に変更する - admin.py編