如何根据父字段的值限制子字段的选择?

时间:2023-01-17 15:35:42

I have several rather complex forms which rely on model hierarchies to assign ForeignKey values. I need to limit the choices available to a child field based upon the value of its parent field. The problem is that the value of a parent field can come from initial data (a GET request) or from bound data (a POST request). Thus, I end up replicating this pattern a lot:

我有几个相当复杂的表单,它们依赖于模型层次结构来分配ForeignKey值。我需要根据子字段的父字段的值限制子字段的可用选项。问题是父字段的值可以来自初始数据(GET请求)或绑定数据(POST请求)。因此,我经常重复这种模式:

class MyForm(forms.Form):
    parent = forms.ModelChoiceField(queryset=Parent.objects.all())
    child = forms.ModelChoiceField(queryset=Child.objects.all())

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)

        # Limit 'child' choices based on current value of 'parent'
        if self.is_bound and self.data.get('parent'):
            self.fields['child'].queryset = Child.objects.filter(parent__pk=self.data['parent'])
        elif self.initial.get('parent'):
            self.fields['child'].queryset = Child.objects.filter(parent=self.initial['parent'])
        else:
            self.fields['child'].choices = []

I get the feeling there's a more efficient way to accomplish this. What am I missing?

我觉得有一种更有效的方法来实现这个目标。我缺少什么?

3 个解决方案

#1


2  

You're in luck. Django Smart Selects make this really simple! You must use a ModelForm (as below) or set up your models with a ChainedForeignKey field type (as seen in the docs).

你是幸运的。Django智能选择使这变得非常简单!您必须使用一个ModelForm(如下所示)或使用一个链edforeignkey字段类型来设置模型(如文档中所示)。

Please note - this is NOT exact code. The arguments provided relate to your model definitions and structure. However, the first option would look something like this:

请注意——这不是确切的代码。提供的参数与模型定义和结构有关。然而,第一个选项看起来是这样的:

from smart_selects.form_fields import ChainedModelChoiceField

class MyForm(forms.ModelForm):
    parent = forms.ModelChoiceField(queryset=Parent.objects.all())
    child = ChainedModelChoiceField('your_app','ModelName','parent','parent')
    class Meta:
        model = YourModel

You must include JQuery in your rendered page in order to use smart selects. When the form fields are rendered, smart selects will include the applicable JQuery code to make Ajax requests when parent is selected, limiting children to choices related to the selected parent.

为了使用智能选择,您必须在呈现的页面中包含JQuery。在呈现表单字段时,smart select将包含适用的JQuery代码,以便在选择父字段时发出Ajax请求,将子字段限制为与所选父字段相关的选项。

#2


0  

For many thousands child field use Ajax.

对于成千上万的子字段,使用Ajax。

urls.py

urls . py

...
url(r'^api/toselect/(?P<parent_id>\d+)/$', views.toselect),
...

in your views.py response json with Childs

在你的观点。py用Childs响应json

...
from django.http import JsonResponse
...
def toselect(request, parent_id=0):
    objs = Child.objects.filter(parent_id=parent_id).values('id', 'name')
    return JsonResponse(list(objs), safe=False)

With Jquery populate a child select when parent value change

使用Jquery填充父值更改时的子选择

$("#id_parent").change(function(){
    var parentId = $("#id_parent").val()
    $.get( base_url + "api/toselect/"+parentId, function( data ) {
        $('#id_child').find('option').remove();

        $(data).each(function(i, v){
            $('#id_child').append('<option value="' + v.id + '">' + v.name+ '</option>');
        })
    });
});

#3


-1  

Generate two select field with all values.

生成两个带有所有值的select字段。

<select id="id_country" name="country">
    <option value="" selected="selected">---------</option>
    <option value="1">Colombia</option>
    <option value="2">Rusia</option>
</select>
<select id="id_city" name="city">
    <option value="" selected="selected">---------</option>
    <option value="1" class="1">Bogotá</option>
    <option value="2" class="2">Moscú</option>
    <option value="3" class="2">San Petersburgo</option>
    <option value="4" class="1">Valledupar</option>
</select>

Using chained Jquery plugin limit the options

使用链式Jquery插件限制了选项

$(function() {
    $("#id_city").chained("#id_country");
});

Reed the complete post in https://axiacore.com/blog/django-y-selects-encadenados/

在https://axiacore.com/blog/django-y-selects-encadenados/中获取完整的文章

#1


2  

You're in luck. Django Smart Selects make this really simple! You must use a ModelForm (as below) or set up your models with a ChainedForeignKey field type (as seen in the docs).

你是幸运的。Django智能选择使这变得非常简单!您必须使用一个ModelForm(如下所示)或使用一个链edforeignkey字段类型来设置模型(如文档中所示)。

Please note - this is NOT exact code. The arguments provided relate to your model definitions and structure. However, the first option would look something like this:

请注意——这不是确切的代码。提供的参数与模型定义和结构有关。然而,第一个选项看起来是这样的:

from smart_selects.form_fields import ChainedModelChoiceField

class MyForm(forms.ModelForm):
    parent = forms.ModelChoiceField(queryset=Parent.objects.all())
    child = ChainedModelChoiceField('your_app','ModelName','parent','parent')
    class Meta:
        model = YourModel

You must include JQuery in your rendered page in order to use smart selects. When the form fields are rendered, smart selects will include the applicable JQuery code to make Ajax requests when parent is selected, limiting children to choices related to the selected parent.

为了使用智能选择,您必须在呈现的页面中包含JQuery。在呈现表单字段时,smart select将包含适用的JQuery代码,以便在选择父字段时发出Ajax请求,将子字段限制为与所选父字段相关的选项。

#2


0  

For many thousands child field use Ajax.

对于成千上万的子字段,使用Ajax。

urls.py

urls . py

...
url(r'^api/toselect/(?P<parent_id>\d+)/$', views.toselect),
...

in your views.py response json with Childs

在你的观点。py用Childs响应json

...
from django.http import JsonResponse
...
def toselect(request, parent_id=0):
    objs = Child.objects.filter(parent_id=parent_id).values('id', 'name')
    return JsonResponse(list(objs), safe=False)

With Jquery populate a child select when parent value change

使用Jquery填充父值更改时的子选择

$("#id_parent").change(function(){
    var parentId = $("#id_parent").val()
    $.get( base_url + "api/toselect/"+parentId, function( data ) {
        $('#id_child').find('option').remove();

        $(data).each(function(i, v){
            $('#id_child').append('<option value="' + v.id + '">' + v.name+ '</option>');
        })
    });
});

#3


-1  

Generate two select field with all values.

生成两个带有所有值的select字段。

<select id="id_country" name="country">
    <option value="" selected="selected">---------</option>
    <option value="1">Colombia</option>
    <option value="2">Rusia</option>
</select>
<select id="id_city" name="city">
    <option value="" selected="selected">---------</option>
    <option value="1" class="1">Bogotá</option>
    <option value="2" class="2">Moscú</option>
    <option value="3" class="2">San Petersburgo</option>
    <option value="4" class="1">Valledupar</option>
</select>

Using chained Jquery plugin limit the options

使用链式Jquery插件限制了选项

$(function() {
    $("#id_city").chained("#id_country");
});

Reed the complete post in https://axiacore.com/blog/django-y-selects-encadenados/

在https://axiacore.com/blog/django-y-selects-encadenados/中获取完整的文章