其实还是挺简单的,由于我的需求只需要在Django后台页面显示,所以只需要在Models那里处理一下就好了。由于我需要的字段比较多,因此在app目录下新建了一个文件cons.py专门存储字段。

以下是模型文件models.py:

# -*- coding: UTF-8 -*- from django.db import models from .cons import SALCATEGORIES from .cons import YEAR from .cons import MONTH from .cons import ORG # Create your models here. class Salary(models.Model): month = models.CharField('月',max_length=50, choices=MONTH) year = models.CharField('年',max_length=10, choices=YEAR) org = models.CharField('组织名',max_length=100, choices=ORG) create_timestamp = models.DateTimeField('创建时间',auto_now_add=True) change_timestamp = models.DateTimeField('修改时间',auto_now=True) def __str__(self): return dict(YEAR)[self.year] dict(MONTH)[self.month] '_' dict(ORG)[self.org] class Meta: db_table = 'salary'

cons.py文件引入的内容如下:

# -*- coding: UTF-8 -*- SALCATEGORIES = ( ('shubas','应发 - 基本工资'), ('shupos','应发 - 岗位工资'), ('shupls','应发 - 绩效工资'), ('shuotr','应发 - 其他'), ('wihuem','扣缴 - 失业保险'), ('wihmed','扣缴 - 医疗保险'), ('wihold','扣缴 - 养老保险'), ('wihgjj','扣缴 - 公积金'), ('wihbgj','扣缴 - 补充住房公积金'), ('wihotr','扣缴 - 其他'), ('relsal','实发 - 实发工资'), ('relotr','实发 - 其他'), ) YEAR = ( ('2020','2020年'), ('2021','2021年'), ('2022','2022年'), ('2023','2023年'), ('2024','2024年'), ('2025','2025年'), ('2026','2026年'), ('2027','2027年'), ('2028','2028年'), ) MONTH = ( ('01','01月'), ('02','02月'), ('03','03月'), ('04','04月'), ('05','05月'), ('06','06月'), ('07','07月'), ('08','08月'), ('09','09月'), ('10','10月'), ('11','11月'), ('12','12月'), ) ORG = ( ('abc','中国abc公司'), ('cde','上海cde公司'), )

这个键值对,存储的是前面的键,显示的是后面的值

上面的这个形式,对于该变量的类型也是一个挺有趣的东西。众所周知( )是个元组的初始化标志,正常来说元组是不能直接转换为字典的,但是上面这样的变量是可以正常转换的,请见如下测试代码和输出:

print(type(ORG)) for i in ORG: print(i[0] "_" i[1]) print(type(i)) print(type(dict(ORG))) print(dict(ORG)) for i in dict(ORG): print(i) print(type(i))

输出:

<class 'tuple'> abc_中国abc公司 <class 'tuple'> cde_上海cde公司 <class 'tuple'> <class 'dict'> {'abc': '中国abc公司', 'cde': '上海cde公司'} abc <class 'str'> cde <class 'str'>

回到实现上来。最终我需要的后台显示情况如下:

django多选字段 DjangoModels处理Select形式字段经验总结(1)

django多选字段 DjangoModels处理Select形式字段经验总结(2)

数据库表存储情况如下:

django多选字段 DjangoModels处理Select形式字段经验总结(3)

这里我们介绍一下Django里模型Field的choices字段:

一个 sequence 本身由正好两个项目的迭代项组成(例如 [(A,B),(A,B)...] ),作为该字段的选择。如果给定了选择,它们会被 模型验证 强制执行,默认的表单部件将是一个带有这些选择的选择框,而不是标准的文本字段。

每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人可读的名称。例如:

YEAR_IN_SCHOOL_CHOICES = [ ('FR', 'Freshman'), ('SO', 'Sophomore'), ('JR', 'Junior'), ('SR', 'Senior'), ('GR', 'Graduate'), ]

一般来说,最好在模型类内部定义选择,并为每个值定义一个合适的名称的常量:

from django.db import models class Student(models.Model): FRESHMAN = 'FR' SOPHOMORE = 'SO' JUNIOR = 'JR' SENIOR = 'SR' GRADUATE = 'GR' YEAR_IN_SCHOOL_CHOICES = [ (FRESHMAN, 'Freshman'), (SOPHOMORE, 'Sophomore'), (JUNIOR, 'Junior'), (SENIOR, 'Senior'), (GRADUATE, 'Graduate'), ] year_in_school = models.CharField( max_length=2, choices=YEAR_IN_SCHOOL_CHOICES, default=FRESHMAN, ) def is_upperclass(self): return self.year_in_school in {self.JUNIOR, self.SENIOR}

虽然你可以在模型类之外定义一个选择列表,然后引用它,但在模型类内定义选择和每个选择的名称,可以将所有这些信息保留在使用它的类中,并帮助引用这些选择(例如,Student.SOPHOMORE 将在导入 Student 模型的任何地方工作)。

你还可以将你的可用选择收集到可用于组织目的的命名组中:

MEDIA_CHOICES = [ ('Audio', ( ('vinyl', 'Vinyl'), ('cd', 'CD'), ) ), ('Video', ( ('vhs', 'VHS Tape'), ('dvd', 'DVD'), ) ), ('unknown', 'Unknown'), ]

每个元组中的第一个元素是应用于该组的名称。第二个元素是一个二元元组的迭代,每个二元元组包含一个值和一个可读的选项名称。分组后的选项可与未分组的选项结合在一个单一的列表中(如本例中的 'unknown' 选项)。

对于每一个设置了 choice 的模型字段,Django 会添加一个方法来检索字段当前值的可读名称。参见数据库 API 文档中的 get_FOO_display()。

请注意,选择可以是任何序列对象——不一定是列表或元组。这让你可以动态地构造选择。但是如果你发现自己把 chips 魔改成动态的,你可能最好使用一个合适的的带有 ForeignKey 的数据库表。 chips 是用于静态数据的,如果有的话,不应该有太大的变化。

每当 choices 的顺序变动时将会创建新的迁移。

除非 blank=False 与 default 一起设置在字段上,否则包含 "---------" 的标签将与选择框一起呈现。要覆盖这种行为,可以在 choices 中添加一个包含 None 的元组,例如 (None, 'Your String For Display') 。另外,你也可以在有意义的地方使用一个空字符串来代替 None ——比如在 CharField。

,