Django 多项选择字段/复选框选择多个
Posted
技术标签:
【中文标题】Django 多项选择字段/复选框选择多个【英文标题】:Django Multiple Choice Field / Checkbox Select Multiple 【发布时间】:2011-02-13 03:57:15 【问题描述】:我有一个 Django 应用程序,想在用户的个人资料中显示多项选择复选框。然后他们将能够选择多个项目。
这是我的 models.py 的简化版本:
from profiles.choices import SAMPLE_CHOICES
class Profile(models.Model):
user = models.ForeignKey(User, unique=True, verbose_name_('user'))
choice_field = models.CharField(_('Some choices...'), choices=SAMPLE_CHOICES, max_length=50)
还有我的表单类:
class ProfileForm(forms.ModelForm):
choice_field = forms.MultipleChoiceField(choices=SAMPLE_CHOICES, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Profile
还有我的views.py:
if request.method == "POST":
profile_form = form_class(request.POST, instance=profile)
if profile_form.is_valid():
...
profile.save()
return render_to_response(template_name, "profile_form": profile_form,, context_instance=RequestContext(request))
我可以看到 POST 只发送一个值:
choice_field u'choice_three'
并且本地 vars 参数正在发送一个列表:
[u'choice_one', u'choice_two', u'choice_three']
所有表单字段显示正确,但是当我提交 POST 时,我收到错误
错误绑定参数 7 - 可能是不受支持的类型。
我是否需要在视图中进一步处理多项选择字段?模型字段类型是否正确?任何帮助或参考将不胜感激。
【问题讨论】:
您能否针对 POST 时遇到的错误发布完整的堆栈跟踪信息? Django Model MultipleChoice的可能重复 【参考方案1】:配置文件选项需要设置为 ManyToManyField 才能正常工作。
所以...你的模型应该是这样的:
class Choices(models.Model):
description = models.CharField(max_length=300)
class Profile(models.Model):
user = models.ForeignKey(User, blank=True, unique=True, verbose_name='user')
choices = models.ManyToManyField(Choices)
然后,同步数据库并使用您想要的各种选项加载 Choices。
现在,ModelForm 将自行构建...
class ProfileForm(forms.ModelForm):
Meta:
model = Profile
exclude = ['user']
最后是视图:
if request.method=='POST':
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
else:
form = ProfileForm()
return render_to_response(template_name, "profile_form": form, context_instance=RequestContext(request))
应该提到的是,您可以通过几种不同的方式设置配置文件,包括继承。也就是说,这也应该对你有用。
祝你好运。
【讨论】:
谢谢布兰特。您指出我的模型类型需要使用 ManyToManyField 关系是正确的。 请注意,使用 save(commit=false) 时需要在表单实例上调用 save_m2m(),否则对关系的更改将不会被保存。见docs.djangoproject.com/en/dev/topics/forms/modelforms/… 我正在尝试实现这一点,但我收到了NameError: name 'TheChoice' is not defined
该解决方案可以作为元组而不是原始问题中的 Choice 模型适用于 Choice 吗?
@brant 也许值得添加一个建议,postgresql 用户可以使用 ArrayFields 来实现相同的功能(甚至更好的性能)【参考方案2】:
Brant 的解决方案绝对正确,但我需要对其进行修改以使其与多个选择复选框和commit=false
一起使用。这是我的解决方案:
models.py
class Choices(models.Model):
description = models.CharField(max_length=300)
class Profile(models.Model):
user = models.ForeignKey(User, blank=True, unique=True, verbose_name_('user'))
the_choices = models.ManyToManyField(Choices)
forms.py
class ProfileForm(forms.ModelForm):
the_choices = forms.ModelMultipleChoiceField(queryset=Choices.objects.all(), required=False, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Profile
exclude = ['user']
views.py
if request.method=='POST':
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
form.save_m2m() # needed since using commit=False
else:
form = ProfileForm()
return render_to_response(template_name, "profile_form": form, context_instance=RequestContext(request))
【讨论】:
关于如何在 django 模板中呈现多选字段的任何建议? 确保在 Choices 模型中定义 __str__() 函数,以便描述文本在模板中呈现为复选框选项。【参考方案3】:models.CharField 是选项之一的 CharField 表示。你想要的是一组选择。这似乎还没有在 django 中实现。
您可以为此使用多对多字段,但这样做的缺点是必须将选择放入数据库中。如果您想使用硬编码选项,这可能不是您想要的。
http://djangosnippets.org/snippets/1200/ 有一个 django sn-p,确实似乎通过实现 ModelField MultipleChoiceField
解决了您的问题。
【讨论】:
【参考方案4】:ManyToManyField 不是一个好的选择。您可以使用一些 sn-ps 来实现 MultipleChoiceField。您可以受到MultiSelectField with comma separated values (Field + FormField) 的启发 但是它有一些bug。你可以安装django-multiselectfield。这个更完美。
【讨论】:
【参考方案5】:我找到的最简单的方法(只是我使用 eval() 将从输入获取的字符串转换为元组以再次读取表单实例或其他地方)
这个技巧效果很好
#model.py
class ClassName(models.Model):
field_name = models.CharField(max_length=100)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.field_name:
self.field_name= eval(self.field_name)
#form.py
CHOICES = [('pi', 'PI'), ('ci', 'CI')]
class ClassNameForm(forms.ModelForm):
field_name = forms.MultipleChoiceField(choices=CHOICES)
class Meta:
model = ClassName
fields = ['field_name',]
【讨论】:
【参考方案6】:您可以使用ArrayField
轻松实现此目的:
# in my models...
tags = ArrayField(models.CharField(null=True, blank=True, max_length=100, choices=SECTORS_TAGS_CHOICES), blank=True, default=list)
# in my forms...
class MyForm(forms.ModelForm):
class Meta:
model = ModelClass
fields = [..., 'tags', ...]
我使用tagsinput JS 库来呈现我的标签,但你可以使用任何你喜欢的东西: 这是我的这个小部件的模板:
% if not hidelabel and field.label %<label for=" field.id_for_label "> field.label </label>% endif %
<input id=" field.id_for_label " type="text" name=" field.name " data-provide="tagsinput"% if field.value % value=" field.value "% endif %% if field.field.disabled % disabled% endif %>
% if field.help_text %<small id=" field.name -help-text" class="form-text text-muted"> field.help_text | safe </small>% endif %
【讨论】:
以上是关于Django 多项选择字段/复选框选择多个的主要内容,如果未能解决你的问题,请参考以下文章