Django:如何创建多选表单?
Posted
技术标签:
【中文标题】Django:如何创建多选表单?【英文标题】:Django: How can I create a multiple select form? 【发布时间】:2013-03-01 20:23:11 【问题描述】:我是 Django/Python 的初学者,我需要创建一个多选表单。我知道这很容易,但我找不到任何例子。我知道如何使用小部件创建 CharField,但我对 fields.py 中的所有选项感到困惑。
例如,我不知道以下哪一项最适合多选表单。
'ChoiceField', 'MultipleChoiceField',
'ComboField', 'MultiValueField',
'TypedChoiceField', 'TypedMultipleChoiceField'
这是我需要创建的表单。
<form action="" method="post" accept-charset="utf-8">
<select name="countries" id="countries" class="multiselect" multiple="multiple">
<option value="AUT" selected="selected">Austria</option>
<option value="DEU" selected="selected">Germany</option>
<option value="NLD" selected="selected">Netherlands</option>
<option value="USA">United States</option>
</select>
<p><input type="submit" value="Continue →"></p>
</form>
编辑:
还有一个小问题。如果我想为每个选项添加一个属性,例如 data:
<option value="AUT" selected="selected" data-index=1>Austria</option>
我该怎么做?
感谢您的帮助!
【问题讨论】:
【参考方案1】:我认为CheckboxSelectMultiple
应该根据您的问题工作。
在您的forms.py
中,编写以下代码:
from django import forms
class CountryForm(forms.Form):
OPTIONS = (
("AUT", "Austria"),
("DEU", "Germany"),
("NLD", "Neitherlands"),
)
Countries = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
choices=OPTIONS)
在您的views.py
中,定义以下函数:
def countries_view(request):
if request.method == 'POST':
form = CountryForm(request.POST)
if form.is_valid():
countries = form.cleaned_data.get('countries')
# do something with your results
else:
form = CountryForm
return render_to_response('render_country.html', 'form': form,
context_instance=RequestContext(request))
在你的render_country.html
:
<form method='post'>
% csrf_token %
form.as_p
<input type='submit' value='submit'>
</form>
【讨论】:
是的,这只是一件小事......如果我想为每个选项添加一个像这样的数据属性 我该怎么做?还缺少最后一个未选择的选项。还是谢谢 不确定!!将表格制作为模型表格。我相信至少在后端会关联一个主键。需要检查一下。 如果我的第一个答案满足您的查询,请考虑接受这个答案。 :) 很好的答案@vibhor,但如代码中所述,"AUT" != "Australia" 是奥地利。很抱歉成为一个书呆子,我们澳大利亚人得到了很多,我们对此有点敏感:-)【参考方案2】:我是这样做的:
forms.py
class ChoiceForm(ModelForm):
class Meta:
model = YourModel
def __init__(self, *args, **kwargs):
super(ChoiceForm, self).__init__(*args, **kwargs)
self.fields['countries'] = ModelChoiceField(queryset=YourModel.objects.all()),
empty_label="Choose a countries",)
urls.py
from django.conf.urls.defaults import *
from django.views.generic import CreateView
from django.core.urlresolvers import reverse
urlpatterns = patterns('',
url(r'^$',CreateView.as_view(model=YourModel, get_success_url=lambda: reverse('model_countries'),
template_name='your_countries.html'), form_class=ChoiceForm, name='model_countries'),)
your_countries.html
<form action="" method="post">
% csrf_token %
form.as_table
<input type="submit" value="Submit" />
</form>
在我的例子中效果很好,如果你需要更多的东西,尽管问我!!
【讨论】:
【参考方案3】:关于我的第二个问题,这是解决方案。扩展类:
from django import forms
from django.utils.encoding import force_unicode
from itertools import chain
from django.utils.html import escape, conditional_escape
class Select(forms.Select):
"""
A subclass of Select that adds the possibility to define additional
properties on options.
It works as Select, except that the ``choices`` parameter takes a list of
3 elements tuples containing ``(value, label, attrs)``, where ``attrs``
is a dict containing the additional attributes of the option.
"""
def render_options(self, choices, selected_choices):
def render_option(option_value, option_label, attrs):
option_value = force_unicode(option_value)
selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
attrs_html = []
for k, v in attrs.items():
attrs_html.append('%s="%s"' % (k, escape(v)))
if attrs_html:
attrs_html = " " + " ".join(attrs_html)
else:
attrs_html = ""
return u'<option value="0"12>3</option>'.format(
escape(option_value), selected_html, attrs_html,
conditional_escape(force_unicode(option_label))
)
'''
return u'<option value="%s"%s%s>%s</option>' % (
escape(option_value), selected_html, attrs_html,
conditional_escape(force_unicode(option_label)))
'''
# Normalize to strings.
selected_choices = set([force_unicode(v) for v in selected_choices])
output = []
for option_value, option_label, option_attrs in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
for option in option_label:
output.append(render_option(*option))
output.append(u'</optgroup>')
else:
output.append(render_option(option_value, option_label,
option_attrs))
return u'\n'.join(output)
class SelectMultiple(forms.SelectMultiple, Select):
pass
例子:
OPTIONS = [
["AUT", "Australia", 'selected':'selected', 'data-index':'1'],
["DEU", "Germany", 'selected':'selected'],
["NLD", "Neitherlands", 'selected':'selected'],
["USA", "United States", ]
]
【讨论】:
【参考方案4】:ModelMultipleChoiceField 是你的朋友。 CharField 能够存储一个选择,但不能存储多个,无需额外的工作,我建议不要这样做。
API doc for ModelMultipleChoiceField
【讨论】:
【参考方案5】:您还可以在表单类中将国家字段定义为
Countries = forms.MultipleChoiceField(widget=forms.SelectMultiple,
choices=OPTIONS_TUPPLE)
我不知道 SelectMultiple 和 CheckboxSelectMultiple 哪个更好,但也可以。
有关更多详细信息,您可以使用有关 widgets 的 django 文档。
【讨论】:
【参考方案6】:当您想要选择多个值时,使用 widget=forms CheckboxSelectMultiple 非常困难。 (记住多选是针对多对多键字段)
在这种情况下 SelectMultiple 更好,因为您可以使用 ctrl 选择多个项目或使用 ctrl+a 选择所有项目。
class MyModalForm(forms.ModelForm):
class Meta:
model = MyModel
widgets =
'products': forms.SelectMultiple(attrs='required': True)
如果你想要多选的动态值,你可以使用 init
class MyModalForm(forms.ModelForm):
class Meta:
model = MyModel
widgets =
'products': forms.SelectMultiple(attrs='required': True)
def __init__(self, *args, **kwargs):
selected_products = kwargs.pop('selected_products', None) ##queryset returned from function
self.fields['products'].queryset = selected_products
self.fields['orders'].queryset = OrderModal.objects.filter(pk=2)
【讨论】:
以上是关于Django:如何创建多选表单?的主要内容,如果未能解决你的问题,请参考以下文章