forms.Form中的ModelChoiceField不会验证是否覆盖了queryset

时间:2014-05-21 18:23:20

标签: django validation django-forms

我有一个django ModelChoiceField,如果我覆盖查询集,则不会验证。

class PersonalNote(forms.Form):
    tile    = ModelChoiceField(queryset=Tile.objects.none())
    note    = forms.CharField()

form = PersonalNote()
form.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)

form.is_valid()错误是:“选择有效选项。该选项不是可用选项之一”。 如果Tile.objects.none()Tile.objects.all()替换,则会验证,但会从数据库中加载太多数据。我也试过了:

class PersonalNote(forms.Form):
    tile    = ModelChoiceField(queryset=Tile.objects.none())
    note    = forms.CharField()

    def __init__(self, *args, **kwargs):
        yyy = kwargs.pop('yyy', None)
        super(PersonalNote, self).__init__(*args, **kwargs)
        if yyy:
            self.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)

这里可能有什么问题?请注意,真正的应用程序也会覆盖标签,但这似乎不是一个因素:

class ModelChoiceField2(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        assert isinstance(obj,Tile)
        return obj.child_title()

3 个答案:

答案 0 :(得分:1)

2小时后我找到了解决方案。因为您在类定义中指定了none的queryset,所以当您实例化要验证的PersonalNote(request.POST)时,它正在引用空查询集

class PersonalNote(forms.Form):
    tile    = ModelChoiceField(queryset=Tile.objects.none())
    note    = forms.CharField() 

要解决此问题,在根据POST请求创建表单时,请确保在检查is_valid()

之前覆盖查询集。
def some_view_def(request):
    form = PersonalNote(request.POST)
    **form.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)**

    if form.is_valid():
         #Do whatever it is

答案 1 :(得分:0)

当您将空的查询集传递给ModelChoiceField时,您说没有任何内容对该字段有效。也许您可以过滤查询集,因此没有太多选项。

答案 2 :(得分:-1)

我也有这个问题。想法是根据条件动态更改ModelChoiceField的查询集(在我的情况下,它是另一个ModelChoiceField制作的过滤器。)

因此,以下一个模型为例:

class FilterModel(models.Model):
    name = models.CharField()

class FooModel(models.Model):
    filter_field = models.ForeignKey(FilterModel)
    name = models.CharField()

class MyModel(models.Model):
    foo_field = models.ForeignKey(FooModel)

如您所见,MyModel的外键为FooModel,但没有FilterModel。因此,为了过滤FooModel选项,我在表单上添加了一个新的ModelChoiceField

class MyForm(forms.ModelForm):
   class Meta:
        model = MyModel

   def __init__(self, *args, **kwargs):
       # your code here
       self.fields['my_filter_field'] = forms.ModelChoiceField(FilterModel, initial=my_filter_field_selected)
       self.fields['my_filter_field'].queryset = FilterModel.objects.all()

然后,您可以在前端上根据所选的foo_field值,使用Ajax加载my_filter_field的选项。在这一点上,一切都应该工作。但是,在加载表单时,它将带来FooModel中的所有可能选项。为避免这种情况,您需要动态更改foo_field的查询集。

在表单视图中,我向MyForm传递了一个新参数:

id_filter_field = request.POST.get('my_filter_field', None)
form = MyForm(data=request.POST, id_filter_field=id_filter_field)

现在,您可以在MyForm上使用该参数来更改查询集:

class MyForm(forms.ModelForm):
    # your code here
    def __init__(self, *args, **kwargs):
        self.id_filter_field = kwargs.pop('id_filter_field', None)
        # your code here
        if self.id_filter_field:
            self.fields['foo_field'].queryset = FooModel.objects.filter(filter_field_id=self.id_filter_field)
        else:
            self.fields['foo_field'].queryset = FooModel.objects.none()