Python django 模型选择选项作为多选框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3582544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:48:50  来源:igfitidea点击:

django model choice option as a multi select box

pythondjangodjango-models

提问by Hellnar

Assuming that I have such model

假设我有这样的模型

COLORS= (
    ('R', 'Red'),
    ('B', 'Yellow'),
    ('G', 'White'),
)
class Car(models.Model):
    name = models.CharField(max_length=20)
    color= models.CharField(max_length=1, choices=COLORS)

It displays as a selectbox in the admin panel however I would like my admin-user to multi select those colors like many-to-many relationship, how can this be achieved without a ('RB', 'Red&Blue'),type of logic

它在管理面板中显示为一个选择框,但是我希望我的管理员用户多选择那些颜色,如多对多关系,如何在没有('RB', 'Red&Blue'),逻辑类型的情况下实现

采纳答案by Manoj Govindan

Can a Carhave multiple colors? In that case colorought to be a many to many relationshiprather than a CharField. If on the other hand you want to do something like Unix permissions(i.e. Red + Blue, Red + Blue + Green etc.) then assign numeric values of to each of them and make coloran integer field.

a 可以Car有多个colors 吗?在那种情况下color应该是多对多关系而不是CharField. 另一方面,如果您想执行诸如Unix 权限之类的操作(即红色 + 蓝色、红色 + 蓝色 + 绿色等),则为它们中的每一个分配数值并创建color一个整数字段

Update

更新

(After reading comment) You can use a custom formto edit your model in Admin instead of the default ModelForm. This custom form can use a multiple choice widget that lets users select multiple colors. You can then override the clean()method of the form to return a suitably concatenated value ('RB' etc.).

(阅读评论后)您可以使用自定义表单在 Admin 中编辑您的模型,而不是默认的ModelForm. 此自定义表单可以使用多项选择小部件,让用户可以选择多种颜色。然后,您可以覆盖clean()表单的方法以返回适当连接的值('RB' 等)。

Update 2

更新 2

Here is some code:

这是一些代码:

First, remove the choices from the model field. Also increase its maximum size to 2. We don't want choices here - if we do, then we'll have to add a choice for each combination of colors.

首先,从模型字段中删除选项。还将其最大大小增加到 2。我们不希望这里有选择——如果我们这样做了,那么我们将不得不为每种颜色组合添加一个选择。

class Car(models.Model):
    ...
    color= models.CharField(max_length=2)

Second add a custom ModelFormto use in admin app. This form will override color and instead declare it as a multiple choice field. We doneed choices here.

其次添加一个自定义ModelForm以在管理应用程序中使用。此表单将覆盖颜色并将其声明为多选字段。我们在这里确实需要选择。

COLORS= (
    ('R', 'Red'),
    ('B', 'Yellow'),
    ('G', 'White'),
)

class CarAdminForm(ModelForm):
    color = forms.MultipleChoiceField(choices = COLORS)

    class Meta:
        model = Car

    def clean_color(self):
        color = self.cleaned_data['color']
        if not color:
            raise forms.ValidationError("...")

        if len(color) > 2:
            raise forms.ValidationError("...")

        color = ''.join(color)
        return color

Note that I have added only a couple of validations. You may want more and/or customize the validations.

请注意,我只添加了几个验证。您可能需要更多和/或自定义验证。

Finally, register this form with admin. Inside your admin.py:

最后,向管理员注册此表单。在您的admin.py:

class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

admin.site.register(Car, CarAdmin)

回答by makapuf

Use a separate table with colors (Red, Blue, Green), and, as you said, add a many to many relationship ? Choice type is not multiple choice, only a string with added UI and checkings.

使用带有颜色(红色、蓝色、绿色)的单独表格,并且如您所说,添加多对多关系?选择类型不是多项选择,只是添加了 UI 和检查的字符串。

Or, generate procedurally your choices with itertools.combinations, example:

或者,使用 itertools.combinations 程序生成您的选择,例如:

choices = zip(
  [''.join(x) for x in itertools.combinations(['','B','R','G'],2)],
  [' '.join(x) for x in itertools.combinations(['','Blue','Red','Green'],2)],
)

 # now choices = [(' Blue', 'B'), (' Red', 'R'), (' Green', 'G'), ('Blue Red', 'BR'), ('Blue Green', 'BG'), ('Red Green', 'RG')]

回答by FallenAngel

For colors tuple, if you use integers instead of chars, you may use commaseparatedintegerfieldfor your model. But Do not forget, commaseparatedintegerfield is a database level structure,so your DBMS must support it.

对于颜色元组,如果使用整数而不是字符,则可以为模型使用逗号分隔整数字段。但是不要忘记,commaseparatedintegerfield 是一个数据库级别的结构,所以你的DBMS 必须支持它。

Documentation link...

文档链接...

回答by Serjik

I've constructed a complete working example with meaningful models. It works perfect. I've tested it on Python 3.4.x and Django 1.8.4. At first I run admin panel and create records for each option in Thema model

我已经用有意义的模型构建了一个完整的工作示例。它完美无缺。我已经在 Python 3.4.x 和 Django 1.8.4 上测试过它。首先我运行管理面板并为 Thema 模型中的每个选项创建记录

models.py

模型.py

from django.db import models

class Author(models.Model):
    fname = models.CharField(max_length=50)
    lname = models.CharField(max_length=80)

    def __str__(self):
        return "{0} {1}".format(self.fname, self.lname)


class Thema(models.Model):
    THEME_CHOICES = (
        ('tech', 'Technical'),
        ('novel', 'Novel'),
        ('physco', 'Phsycological'),
    )
    name = models.CharField(max_length=20,choices=THEME_CHOICES, unique=True)

    def __str__(self):
        return self.name

class Book(models.Model):

    name = models.CharField(max_length=50)
    author = models.ForeignKey(Author)
    themes = models.ManyToManyField(Thema)

    def __str__(self):
        return "{0} by {1}".format(self.name,self.author)

forms.py

表格.py

from django import forms

from .models import *

class BookForm(forms.ModelForm):
    themes = forms.ModelMultipleChoiceField(queryset=Thema.objects, widget=forms.CheckboxSelectMultiple(), required=False)

admin.py

管理文件

from django.contrib import admin

from .models import *
from .forms import *

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass


@admin.register(Book)    
class BookAdmin(admin.ModelAdmin):
    form = BookForm


@admin.register(Thema)
class ThemaAdmin(admin.ModelAdmin):
    pass

回答by younesfmgtc

The easiest way I found (just I use eval() to convert string gotten from input to tuple to read again for form instance or other place)

我找到的最简单的方法(只是我使用 eval() 将从输入获得的字符串转换为元组以再次读取表单实例或其他地方)

This trick works very well

这个技巧效果很好

#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()
            ...