动态设置的MultipleChoiceField的验证,字段最初为空怎么办?
我有一个页面,上面有几个不同的表单。第一个表单里有一个搜索框,用户在这里输入内容后,会自动生成一个多选框。用户输入查询后,系统会通过AJAX(就是一种可以在不刷新页面的情况下与服务器交换数据的技术)发送请求,获取所有符合条件的记录。然后,用户可以从这个多选框中选择想要的选项,点击“添加”按钮,把这些选项移动到另一个多选框里。
这个过程本身是没问题的,但当我提交表单时,系统却报错,提示“选择一个有效的选项。1不是可用选项之一。”我尝试在表单初始化时设置选项,但似乎没有效果。
我的表单代码:
class SiteCoordinatorForm(forms.ModelForm):
selected_studies = forms.MultipleChoiceField(required = False)
site = forms.ChoiceField(required = False)
studies = forms.MultipleChoiceField(required = False)
study_search = forms.CharField(max_length = 50, required = False)
def __init__(self, *args, **kwargs):
super(SiteCoordinatorForm, self).__init__(*args, **kwargs)
if args:
study_list = []
query_dict = args[0]
self.fields['selected_studies'].choices = [(int(x), x) for x in query_dict.getlist('selected_studies')]
self.fields['site'].choices = [(x.pk, "%s (%s)" % (x.primary_name, x.primary_number)) for x in Site.objects.all().order_by('primary_name')]
class Meta:
model = SiteCoordinator
exclude = ('studies', 'site', 'selected_studies')
我的AJAX函数,用来填充选项框:
def search_studies(request):
return_data = {}
studies = []
make_query = lambda terms, fieldname: reduce(lambda x, y: x & Q(**{fieldname + '__icontains': y}), terms, Q())
if 'search_text' in request.POST:
terms = request.POST['search_text'].split()
for rec in Study.objects.filter(make_query(terms, 'name')):
studies.append({
'study': {'id': rec.id, 'name': rec.name, 'number': rec.id}
})
response = {'status': 'success', 'count': len(studies), 'studies': studies}
return HttpResponse(simplejson.dumps(response), mimetype="application/json")
用来填充多选框的函数:
function show_results(data, status_code, request){
recs = data.studies;
var select_box = document.getElementById('id_studies');
select_box.options.length = 0;
for (var index = 0; index < recs.length; index ++){
select_box.options[index] = new Option(recs[index].study.name,
recs[index].study.id,
false, false);
}
}
然后是用来移动选项的JQuery代码:
$('#add').click(function() {
$('#id_studies option:selected').remove().appendTo('#id_selected_studies');
return false;
});
$('#remove').click(function() {
$('#id_selected_studies option:selected').remove().appendTo('#id_studies');
return false;
});
2 个回答
0
这里有一个例子,使用了@AnuragUniyal提出的解决方案,同时也回应了@JohnLehmann的评论:
class MyForm(forms.Form):
new_tags = forms.CharField(required=False, widget=forms.SelectMultiple)
def save(self, commit=True):
instance = super(MyForm, self).save(commit=commit)
for tag in eval(self.cleaned_data['new_tags']):
models.Tag.objects.get_or_create(name=tag)
return instance
基本上,我们通过对这个包含unicode字符串的列表进行eval()
操作,将它转换回Python列表。
5
很明显,我们不想对MultipleChoiceField
进行验证,但我们希望使用MultipleSelectWidget
。所以解决办法就是把字段改成
studies = forms.CharField(widget=forms.SelectMultiple)
然后在
def clean_studies(self):
...
里自己进行验证。