【问题标题】:Django Multiple Choice Field / Checkbox Select MultipleDjango 多项选择字段/复选框选择多个
【发布时间】: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 - 可能是不受支持的类型。

我是否需要在视图中进一步处理多项选择字段?模型字段类型是否正确?任何帮助或参考将不胜感激。

【问题讨论】:

标签: python django select checkbox


【解决方案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 %}
        

        【讨论】:

          猜你喜欢
          • 2021-05-20
          • 1970-01-01
          • 1970-01-01
          • 2016-03-22
          • 2010-11-19
          • 1970-01-01
          • 2016-07-09
          • 1970-01-01
          • 2018-05-06
          相关资源
          最近更新 更多