python Django多项选择字段/复选框选择多个

pxq42qpu  于 2023-04-04  发布在  Python
关注(0)|答案(7)|浏览(300)

我有一个Django应用程序,希望在用户配置文件中显示多个选择复选框。这样他们就可以选择多个项目。
这是我的www.example.com的简化版本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)

我的form class:

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时出错-可能是不支持的类型。
我是否需要在视图中进一步处理多项选择字段?模型字段类型是否正确?任何帮助或参考将不胜感激。

lymgl2op

lymgl2op1#

配置文件选项需要设置为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))

应该提到的是,你可以用几种不同的方式来设置配置文件,包括继承。也就是说,这对你来说也是有效的。
祝你好运。

mxg2im7a

mxg2im7a2#

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

vhipe2zx3#

models.CharField是其中一个选项的CharField表示。你想要的是一组选项。这似乎还没有在django中实现。
你可以使用多对多的字段,但是这样做的缺点是选择必须放在数据库中。如果你想使用硬编码的选择,这可能不是你想要的。
http://djangosnippets.org/snippets/1200/上有一个django代码片段,它似乎通过实现ModelField MultipleChoiceField解决了你的问题。

aiazj4mn

aiazj4mn4#

ManyToManyField不是一个好的选择,你可以使用一些片段来实现MultipleChoiceField,你可以从MultiSelectField with comma separated values (Field + FormField)中得到启发,但它有一些bug,你可以安装django-multiselectfield,这样更完美。

camsedfj

camsedfj5#

我发现的最简单的方法(只是我使用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',]
avwztpqn

avwztpqn6#

您可以使用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 %}
wrrgggsh

wrrgggsh7#

我已经实现了一个非常简单的表单字段,它可以在CharField之间进行转换:

from django.forms import ModelForm, MultipleChoiceField, ValidationError, CheckboxSelectMultiple
from spellbook.models import MyModel

class CheckboxSelectMultipleAsCharField(CheckboxSelectMultiple):
    def format_value(self, value):
        if value is not None and isinstance(value, str):
            value = list(value)
        return super().format_value(value)

class MultipleChoiceFieldAsCharField(MultipleChoiceField):
    widget = CheckboxSelectMultipleAsCharField
    def to_python(self, value):
        return ''.join(super().to_python(value))

    def validate(self, value):
        super().validate(value)
        if len(value) > len(self.choices):
            raise ValidationError('Too many choices.')


class MyModelForm(ModelForm):
    my_char_field = MultipleChoiceFieldAsCharField(choices=MyModel.OptionsEnum.choices, required=True)
    ...

相关问题