Django模型选择选项作为多选框
假设我有这样的模型
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)
它在管理面板中显示为一个下拉框,但我希望我的管理员用户能够像处理多对多关系那样,选择多个颜色。请问我该如何做到这一点,而不使用类似 ('RB', 'Red&Blue'),
这样的逻辑呢?
6 个回答
使用一个单独的表格来存储颜色(红色、蓝色、绿色),然后,正如你所说,添加一个多对多的关系?选择的类型不是多选,只是一个字符串,并且有额外的用户界面和检查。
或者,可以用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')]
我做了一个完整的示例,里面有一些有意义的模型。它运行得非常好。我在Python 3.4.x和Django 1.8.4上测试过。
首先,我启动了管理面板,并为每个选项在Thema模型中创建了记录。
模型文件:models.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
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
一辆Car
可以有多种color
吗?如果可以的话,color
就应该是一个多对多关系,而不是一个CharField
。另一方面,如果你想做类似Unix权限的事情(比如红色+蓝色,红色+蓝色+绿色等等),那么给每种颜色分配一个数字值,把color
设置为一个整数字段。
更新
(看了评论后)你可以使用自定义表单来在管理后台编辑你的模型,而不是使用默认的ModelForm
。这个自定义表单可以使用一个多选组件,让用户选择多种颜色。然后你可以重写表单的clean()
方法,返回一个合适的拼接值(比如'RB'等等)。
更新 2
这里有一些代码:
首先,从模型字段中移除选项。同时把它的最大大小增加到2。我们这里不需要选项——如果需要的话,就得为每种颜色组合添加一个选项。
class Car(models.Model):
...
color= models.CharField(max_length=2)
其次,添加一个自定义的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
注意,我只添加了一些验证。你可能想要更多的验证,或者自定义验证。
最后,将这个表单注册到管理后台。在你的admin.py
文件中:
class CarAdmin(admin.ModelAdmin):
form = CarAdminForm
admin.site.register(Car, CarAdmin)