我有一个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()
答案 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()