Django 多选字段 / 多选框选择多个

43 投票
7 回答
126822 浏览
提问于 2025-04-15 22:06

我有一个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' 

而本地变量params却发送了一个列表:

[u'choice_one', u'choice_two', u'choice_three']

所有的表单字段显示都正确,但当我提交POST请求时,出现了一个错误

错误绑定参数7 - 可能是不支持的类型。

我需要在视图中进一步处理这个多选字段吗?模型字段类型正确吗?任何帮助或参考资料都将非常感激。

7 个回答

13

models.CharField 是用来表示你选择的选项之一的字符字段。你其实想要的是一组选择。看起来在 Django 中还没有实现这个功能。

你可以使用多对多字段来实现,但这样有个缺点,就是这些选择必须存储在数据库里。如果你想要的是硬编码的选择,这样做可能就不太合适了。

在这个链接 http://djangosnippets.org/snippets/1200/ 上,有一个 Django 的代码片段,似乎可以解决你的问题,它实现了一个 ModelField 的 MultipleChoiceField

19

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))
41

为了让这个功能正常工作,个人资料的选择需要设置为多对多字段。

所以,你的模型应该像这样:

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)

接下来,更新数据库,并加载你想要的各种选项到选择中。

现在,模型表单会自动生成...

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))

值得一提的是,你可以用几种不同的方式来设置个人资料,包括继承。不过,这种方法对你来说也应该有效。

祝你好运。

撰写回答