【问题标题】:Get queryset for ModelMultipleChoiceField field based on ModelChoiceField基于 ModelChoiceField 获取 ModelMultipleChoiceField 字段的查询集
【发布时间】:2015-09-09 03:02:59
【问题描述】:

我需要表单,用户可以在其中根据所选标签选择游览。我已经通过视图、自定义 html 表单和一些 AJAX 东西实现了它:

HTML 表单:

<form id="add-destination" method="post">
    {% csrf_token %}
    <select name="tag_id" id="tag_id">
        <option value=''>---</option>
        {% for tag in tags %}
        <option value={{ tag.id }}>{{ tag.name }}</option>
        {% endfor %}
    </select></br>
    <select multiple="multiple" name="tours" id="tours">
    </select></br>
    <button type="submit">Submit</button>
</form>

按标签查看以获取游览

def get_tours_by_tag(request):
    tag_id = Tag.objects.get(id=request.GET.get('tag_id', None))
    tours = Inbound.objects.filter(tags=tag_id)
    return JsonResponse({"status": "ok", "tours": serializers.serialize("json", list(tours))})

JS:

$(function(){
    $('#tag_id').change(function(e){
        $('#tours').html('');
        e.preventDefault();
        $.ajax({
            type: 'GET',
            data: $(e.currentTarget).serialize(),
            url: "/ru/tour/get_tours/",
            success: function(data){
               var tour_data = JSON.parse(data.tours);
               if(data.status=='ok'){
                   $.each(tour_data, function(i, item) {
                       $('#tours').append('<option value='+item['pk']+'>'+item['fields']['title']+'</option>');
                   });
               }else{
                 console.log("Not okay!")
               }
            }
        });
    })
});

这种方法效果很好,但我知道这不是解决此类问题的正确方法。我想通过使用 django 表单的力量来做到这一点。

所以我有模特之旅:

class Tour(models.Model):
    title = models.CharField(max_length=255)
    tags = models.ManyToManyField(Tag)

和形式:

class FiveDestinationForm(forms.Form):
    tags = forms.ModelChoiceField(queryset=Tag.objects.all())
    tours = forms.ModelMultipleChoiceField(queryset=????)

    fields = ('tag', 'tours')

我发现了一些足够接近的问题,并尝试通过覆盖表单中的__init__ 方法来解决我的问题,正如建议的那样:

class MyForm(forms.Form):
    tags = forms.ModelChoiceField(queryset=Tag.objects.all())
    tours = forms.ModelMultipleChoiceField(queryset=Tour.objects.none())

    def __init__(self, *args, **kwargs):
        qs = kwargs.pop('tours', None)
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['tours'].queryset = qs

    fields = ('tag', 'tours')

但我收到以下错误:

'NoneType' 对象没有属性'iterator'

所以我的问题是如何根据用户在 ModelChoiceField 中选择的内容正确设置 ModelMultipleChoiceField 的查询集?

【问题讨论】:

    标签: python django forms django-forms


    【解决方案1】:

    您看到的错误很可能是因为表单没有收到“tours”参数(它将收到一个名为 data 的字典,其中包含未经验证的表单中的字段数据),因此 @987654322 @ 变量将为无。

    你可能应该这样做:

    class MyForm(forms.Form):
        tag = forms.ModelChoiceField(queryset=Tag.objects.all())
        tours = forms.ModelMultipleChoiceField(queryset=Tour.objects.none())
    
        def __init__(self, *args, **kwargs):
            super(MyForm, self).__init__(*args, **kwargs)
    
            if kwargs['data']:
                tag_id = kwargs['data'].get('tag', None)
                if tag_id:
                    self.fields['tours'].queryset = Tour.objects.filter(tag_id=tag_id)
    

    请注意,我们在这里稍微绕过了 django 的表单机制,需要自己解析 tag_id。不过,这没什么大不了的。

    从用户体验的角度来看,这是一个在不使用 ajax 的情况下很难解决的问题。所以我也不会完全否定你的解决方案。

    【讨论】:

      猜你喜欢
      • 2014-11-15
      • 2011-12-31
      • 2017-09-18
      • 1970-01-01
      • 2019-11-16
      • 2011-11-28
      • 2018-02-01
      • 1970-01-01
      • 2011-07-13
      相关资源
      最近更新 更多