我想构建一个国家/州选择器。首先选择一个国家,该国家的州显示在第二个选择框中。在PHP和jQuery中做这件事相当容易,但我发现Django forms在这方面有一些限制。
我可以在页面加载时将State字段设置为空,然后用一些jQuery填充它,但是如果有表单错误,它将无法“记住”您选择的State。我也非常确定它将抛出一个验证错误,因为您的选择不在表单中列出的Python方面。
那么我该如何解决这些问题呢?
发布于 2010-07-13 11:03:07
您可以将隐藏字段设置为具有实际的“<select>”值,然后使用jQuery创建状态列表,并在.select()上将其值复制到隐藏字段。然后,在页面加载时,jQuery代码可以获取隐藏字段的值,并在填充后使用它在<select>元素中选择正确的项。
这里的关键概念是,州弹出菜单是完全用jQuery创建的虚构的,而不是Django表单的一部分。这使您可以完全控制它,同时让所有其他字段正常工作。
编辑:还有另一种方法,但它不使用Django的表单类。
在视图中:
context = {'state': None, 'countries': Country.objects.all().order_by('name')}
if 'country' in request.POST:
context['country'] = request.POST['country']
context['states'] = State.objects.filter(
country=context['country']).order_by('name')
if 'state' in request.POST:
context['state'] = request.POST['state']
else:
context['states'] = []
context['country'] = None
# ...Set the rest of the Context here...
return render_to_response("addressform.html", context)然后在模板中:
<select name="country" id="select_country">
{% for c in countries %}
<option value="{{ c.val }}"{% ifequal c.val country %} selected="selected"{% endifequal %}>{{ c.name }}</option>
{% endfor %}
</select>
<select name="state" id="select_state">
{% for s in states %}
<option value="{{ s.val }}"{% ifequal s.val state %} selected="selected"{% endifequal %}>{{ s.name }}</option>
{% endfor %}
</select>当国家发生变化时,您还需要通常的JavaScript来重新加载州选择器。
我还没有测试过这一点,所以它可能有几个漏洞,但它应该能让人理解这个想法。
所以你的选择是:
MultiWidget中使用几个Select,而后者在常规文档中没有文档记录,因此您必须阅读源代码。发布于 2011-12-20 20:18:14
这是我的解决方案。它使用未记录的表单方法_raw_value()来查看请求的数据。这适用于表单,表单也有前缀。
class CascadeForm(forms.Form):
parent=forms.ModelChoiceField(Parent.objects.all())
child=forms.ModelChoiceField(Child.objects.none())
def __init__(self, *args, **kwargs):
forms.Form.__init__(self, *args, **kwargs)
parents=Parent.objects.all()
if len(parents)==1:
self.fields['parent'].initial=parents[0].pk
parent_id=self.fields['parent'].initial or self.initial.get('parent') \
or self._raw_value('parent')
if parent_id:
# parent is known. Now I can display the matching children.
children=Child.objects.filter(parent__id=parent_id)
self.fields['children'].queryset=children
if len(children)==1:
self.fields['children'].initial=children[0].pkjquery代码:
function json_to_select(url, select_selector) {
/*
Fill a select input field with data from a getJSON call
Inspired by: http://stackoverflow.com/questions/1388302/create-option-on-the-fly-with-jquery
*/
$.getJSON(url, function(data) {
var opt=$(select_selector);
var old_val=opt.val();
opt.html('');
$.each(data, function () {
opt.append($('<option/>').val(this.id).text(this.value));
});
opt.val(old_val);
opt.change();
})
}
$(function(){
$('#id_parent').change(function(){
json_to_select('PATH_TO/parent-to-children/?parent=' + $(this).val(), '#id_child');
})
});回调代码,返回JSON:
def parent_to_children(request):
parent=request.GET.get('parent')
ret=[]
if parent:
for children in Child.objects.filter(parent__id=parent):
ret.append(dict(id=child.id, value=unicode(child)))
if len(ret)!=1:
ret.insert(0, dict(id='', value='---'))
return django.http.HttpResponse(simplejson.dumps(ret),
content_type='application/json')发布于 2010-07-13 13:07:24
基于Mike的建议:
// the jQuery
$(function () {
var $country = $('.country');
var $provInput = $('.province');
var $provSelect = $('<select/>').insertBefore($provInput).change(function() {
$provInput.val($provSelect.val());
});
$country.change(function() {
$provSelect.empty().addClass('loading');
$.getJSON('/get-provinces.json', {'country':$(this).val()}, function(provinces) {
$provSelect.removeClass('loading');
for(i in provinces) {
$provSelect.append('<option value="'+provinces[i][0]+'">'+provinces[i][1]+'</option>');
}
$provSelect.val($provInput.val()).trigger('change');
});
}).trigger('change');
});
# the form
country = CharField(initial='CA', widget=Select(choices=COUNTRIES, attrs={'class':'country'}))
province = CharField(initial='BC', widget=HiddenInput(attrs={'class':'province'}))
# the view
def get_provinces(request):
from django.utils import simplejson
data = {
'CA': CA_PROVINCES,
'US': US_STATES
}.get(request.GET.get('country', None), None)
return HttpResponse(simplejson.dumps(data), mimetype='application/json')https://stackoverflow.com/questions/3233850
复制相似问题