Django模型多选

时间:2014-12-12 09:47:18

标签: python django django-models

我知道模型没有MultipleChoiceField,您只能在表单上使用它。

今天,在分析与多项选择相关的新项目时,我遇到了一个问题。

我希望有CharField字段和choices字段,可以选择多项选项。

我通过创建CharField来解决此问题,并使用forms.MultipleChoiceField管理表单中的多个选项,并以逗号分隔选项。

在这个项目中,由于配置问题,我不能像上面提到的那样去做,我需要在模型中进行,我更喜欢 NOT 来编辑 Django管理表单< / em> 既不也使用表单。 我需要一个具有多个选项的模型字段选项

  • 有人通过模特解决了这样的问题吗?

也许覆盖一些模型功能或使用自定义小部件......我不知道,我有点迷失在这里。


修改

我知道简单选择,我希望有类似的内容:

class MODEL(models.Model):
    MY_CHOICES = (
        ('a', 'Hola'),
        ('b', 'Hello'),
        ('c', 'Bonjour'),
        ('d', 'Boas'),
    )
    ...
    ...
    my_field = models.CharField(max_length=1, choices=MY_CHOICES)
    ...

但能够保存多项选择,而不仅仅是一种选择。

7 个答案:

答案 0 :(得分:45)

您需要考虑如何在数据库级别存储数据。这将决定您的解决方案。

据推测,您希望表中存储多个值的单个列。这也会强迫您考虑如何序列化 - 例如,如果您需要存储可能包含逗号的字符串,则不能简单地用逗号分隔。

但是,您最好使用如下之一的解决方案:

答案 1 :(得分:8)

从这两个中,https://pypi.python.org/pypi/django-select-multiple-field/看起来更圆润,更完整。它甚至有一套很好的单元测试。

我发现的问题是它在实现模型字段的类中抛出了Django 1.10弃用警告。

我修好了这个并发了PR。最新的代码,直到他们合并我的PR(如果他们决定嘿嘿)是在我的回购分支中,在这里:https://github.com/matiasherranz/django-select-multiple-field

干杯!

中号.-

答案 2 :(得分:2)

在您的情况下,我使用了ManyToManyField

会是这样的:

class MY_CHOICES(models.Model)
    choice = models.CharField(max_length=154, unique=True)

class MODEL(models.Model):
    ...
    ...
    my_field = models.ManyToManyField(MY_CHOICES)

所以,现在您可以选择多个选择

答案 3 :(得分:0)

如果您希望窗口小部件看起来像文本输入,并且仍然可以从建议中选择多个选项,那么您可能正在寻找Select2。还有django-select2将它与Django Forms和Admin集成。

答案 4 :(得分:0)

您可以将IntegerField用于模型,将2的幂用于选择(位图字段)。我不确定为什么Django尚未内置此功能。

class MyModel(models.Model):
    A = 1
    B = 2
    C = 4
    MY_CHOICES = ((A, "foo"), (B, "bar"), (C, "baz"))
    my_field = models.IntegerField(default=0)


from functools import reduce


class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
    
    # it can be set to required=True if needed
    my_multi_field = forms.TypedMultipleChoiceField(
        coerce=int, choices=MyModel.MY_CHOICES, required=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['my_multi_field'].initial = [
            c for c, _ in MyModel.MY_CHOICES
            if self.instance.my_field & c
        ]

    def save(self, *args, **kwargs):
        self.instance.my_field = reduce(
            lambda x, y: x | y,
            self.cleaned_data.get('my_multi_field', []),
            0)
        return super().save(*args, **kwargs)

可以像这样查询:MyModel.objects.filter(my_field=MyModel.A | MyModel.C)以获取所有设置了A和C的记录。

答案 5 :(得分:0)

from django.db import models

class KarModel(models.Model):
    choose_gender = (
        (True, 'Male'),
        (False, 'Female'),
    )
    fullname= models.CharField(max_length=200)
    gender = models.BooleanField(default=True, choices=choose_gender)

    def __str__(self):
        return self.fullname

简单方法

答案 6 :(得分:-1)

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

#view.py
def viewfunction(request, pk):
    ins = ClassName.objects.get(pk=pk)

    form = ClassNameForm(instance=ins)
    if request.method == 'POST':
        form = form (request.POST, instance=ins)
        if form.is_valid():
            form.save()
            ...