Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django/jQuery级联选择框?_Django_Jquery_Django Forms - Fatal编程技术网

Django/jQuery级联选择框?

Django/jQuery级联选择框?,django,jquery,django-forms,Django,Jquery,Django Forms,我想建立一个国家/州选择器。首先选择一个国家,该国家的州将显示在第二个选择框中。在PHP和jQuery中这样做相当容易,但我发现Django表单在这方面有点限制 我可以在页面加载时将State字段设置为空,然后用一些jQuery填充它,但是如果出现表单错误,它将无法“记住”您选择的状态。我也很确定它会抛出一个验证错误,因为您的选择不是Python方面表单中列出的选项之一 那么我该如何解决这些问题呢?您可以将一个隐藏字段设置为具有真正的“状态”值,然后使用jQuery创建列表,并在.select(

我想建立一个国家/州选择器。首先选择一个国家,该国家的州将显示在第二个选择框中。在PHP和jQuery中这样做相当容易,但我发现Django表单在这方面有点限制

我可以在页面加载时将State字段设置为空,然后用一些jQuery填充它,但是如果出现表单错误,它将无法“记住”您选择的状态。我也很确定它会抛出一个验证错误,因为您的选择不是Python方面表单中列出的选项之一


那么我该如何解决这些问题呢?

您可以将一个隐藏字段设置为具有真正的“状态”值,然后使用jQuery创建
列表,并在
.select()
上将其值复制到隐藏字段。然后,在页面加载时,jQuery代码可以获取隐藏字段的值,并在填充后使用它在
元素中选择正确的项

这里的关键概念是,状态弹出菜单是完全在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>

{国家/地区中c的百分比%}
{{c.name}}
{%endfor%}
{s在%s状态下的%s}
{{s.name}}
{%endfor%}
当国家发生变化时,您还需要使用常规JavaScript重新加载状态选择器

我还没有测试过这个,所以可能有几个洞,但它应该能让人理解这个想法

因此,您的选择是:

  • 使用Django表单中的隐藏字段作为实际值,并通过AJAX在客户端创建选择菜单,或
  • 抛弃Django的表单,自己初始化菜单
  • 创建一个,我没有这样做,因此不会评论。我不知道这是否可行,但看起来您需要在
    多窗口小部件中选择几个
    Select
    ,后者未记录在常规文档中,因此您必须阅读源代码

根据迈克的建议:

// 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')
//jQuery
$(函数(){
变量$country=$(“.country”);
变量$provInput=$('.PROVICE');
var$provSelect=$(“”).insertBefore($provInput).change(函数(){
$provInput.val($provSelect.val());
});
$country.change(函数(){
$provSelect.empty().addClass('loading');
$.getJSON('/get-Providences.json',{country':$(this.val()}),函数(省){
$provSelect.removeClass('loading');
(我在各省){
$provSelect.append(“”+省[i][1]+“”);
}
$provSelect.val($provInput.val()).trigger('change');
});
}).触发(“变更”);
});
#形式
country=CharField(initial='CA',widget=Select(choices=COUNTRIES,attrs={'class':'country'}))
省=CharField(initial='BC',widget=HiddenInput(attrs={'class':'province'}))
#景色
def get_省(请求):
从django.utils导入simplejson
数据={
“CA”:CA_省,
“美国”:美国各州
}.get(request.get.get('country',None),None)
返回HttpResponse(simplejson.dumps(数据),mimetype='application/json')

这是我的解决方案。它使用未记录的表单方法\u raw\u 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].pk
jquery代码:

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');
     })  
    });

那是个聪明的主意。看起来有点脏,但我可以忍受。如果有适当的文件记录,就不会脏^_-只是我似乎不需要一个隐藏的元素来绕过Django的一些怪癖。Django并不真的做变异形式。无论何时,只要我有一个表单,我就自己做。也不太喜欢你的编辑,尽管它是可行的:p我现在将坚持使用隐藏输入/AJAX sol'n。嗯。。。还没有将函数传递给jQuery,所以我不确定它的作用。通常我看到
(函数($){…})(jQuery)$
不是
jQuery
时,使用code>。此外,在
for(i in provings)
循环中,我将使用
$('').val(provings[i][0]).text(provings[i][1]).appendTo($provSelect)。我猜我的方式比较慢,但是当你把每一个条款放在一行上时,它更容易阅读。此外,在IIRC中,您可以使用
$('id_country')
而不是
$('.country')
;“省”小部件也是如此,它可以让您转储表单中的
内容。@Mike:
$(function()
$(document)的缩写。ready(function())
。我故意使用一个类,因为在一个页面上可能有多个国家/省选择器…这并不是说此脚本将按原样处理多个国家/省选择器。尝试此操作对我帮助很大。但是_raw_value()从1.9开始被删除。我正在使用以下命令:。有人知道捕获未提交值的更好方法吗?非常感谢。
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')