原作Adam Johnson, 大江狗翻译整理,原文链接见本文结尾。
Django 3.0的主要新增功能之一是对模型字段选择的枚举。它是一种定义和约束模型Field.choices的更好方法。
以前在Django模型中通常会通过定义一些“常量”和元组来定义choices,如下所示:
from django.db import models
class Book(models.Model):
UNPUBLISHED = 'UN'
PUBLISHED = 'PB'
STATUS_CHOICES = [
(UNPUBLISHED, 'Unpublished'),
(PUBLISHED, 'Published'),
status = models.CharField(
max_length=2,
choices=STATUS_CHOICES,
default=UNPUBLISHED,
然后其他人可以按如下方式使用这些常量,例如:
unpublished_books = Book.objects.filter(status=Book.UNPUBLISHED)
如果多个模型使用同一组选项choices和常量,则可能需要把choices选项和常量从模型级别而转到模块级别,此时再也不能在通过Book.UNPUBLISHED的获取常量内容了。
from django.db import models
UNPUBLISHED = 'UN'
PUBLISHED = 'PB'
STATUS_CHOICES = [
(UNPUBLISHED, 'Unpublished'),
(PUBLISHED, 'Published'),
class Book(models.Model):
status = models.CharField(
max_length=2,
choices=STATUS_CHOICES,
default=UNPUBLISHED,
class Pamphlet(models.Model):
status = models.CharField(
max_length=2,
choices=STATUS_CHOICES,
default=PUBLISHED,
这样在models.py文件中留下一堆没有命名空间的常量, 这有点违反《 Python之禅》:
命名空间是一个很棒的主意–让我们做更多的事!
这也使我们缺少一些有用的功能。例如,没有简单的方法可以将值转换为其显示标签。
更新(2020年1月28日): 老版模型实例Django了提供get_FOO_display()
方法来转换值choice选项值对应的标签。
存在诸如django-choices和django-enumfields之类的软件包来解决这些问题。我还看到了其他项目上几个类似功能的自定义实现。
Django 3.0现在提供了一个Choices
带有两个子类类IntegerChoices
和TextChoices
。这些类扩展了Python的Enum
类型,并增加了额外的约束和功能,以使其适用于Field.choices
。
现在我们要转换之前的示例,我们定义一个新的Status类,该类继承了TextChoices类,用于替换我们之前定义的STATUS_CHOICES元组。现在Status.choices与STATUS_CHOICES是等同的。除此以外,你还可以使用Status.UNPUBLISHED的方式调用Status类下的常量。此时常量UNPUBLISHED有了自己的命名空间,更安全,也使代码可读性更高。
from django.db import models
class Status(models.TextChoices):
UNPUBLISHED = 'UN', 'Unpublished'
PUBLISHED = 'PB', 'Published'
class Book(models.Model):
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.UNPUBLISHED,
class Pamphlet(models.Model):
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.PUBLISHED,
我们可以通过检查未检测到迁移变化来测试是否正确转换:
$python manage.py makemigrations --dry-run
No changes detected
如果我们添加,删除或重新排序了任何成员,则这将被检测为字段中的更改。这是因为迁移框架仅看到由choices
生成的列表Status.choices
,而看不到枚举类。
QuerySet过滤器可以更新为使用以下Choices
类:
unpublished_books = Book.objects.filter(status=Status.UNPUBLISHED)
我们还可以轻松地将值转换为其显示标签:
In [2]: book = Book.objects.latest('id')
In [3]: Status(book.status)
Out[3]: <Status.UNPUBLISHED: 'UN'>
In [4]: Status(book.status).label
Out[4]: 'Unpublished'
我希望这可以帮助您享受这一新的Django 3.0功能。该枚举类型的文件涵盖了一些细节,值得一读。感谢Shai Berger,Nick Pope,Marius Felisiak,Carlton Gibson,以及所有其他负责添加它的人(票号#27910)。
原文链接:https://adamj.eu/tech/2020/01/27/moving-to-django-3-field-choices-enumeration-types/
支持异步的Django 3.X来了,你准备好了吗? Django 3.0新特色与变化详解。
原作Adam Johnson, 大江狗翻译整理,原文链接见本文结尾。Django 3.0的主要新增功能之一是对模型字段选择的枚举。它是一种定义和约束模型Field.choices的更好方...
提供带有可重用枚举和过渡验证的枚举Django模型字段(使用IntegerField )。
当前,Django 1.11-3.1版和Python 2.7、3.4-3.8版。
在您的Python环境中安装django-enumfield :
$ pip install django-enumfield
从django-enumfield 1.x升级?
要与1.8之前的Django版本一起使用,请使用版
要与1.11之前的Django版本一起使用,请使用版
创建一个Enum类,并将其作为第一个参数传递给Django模型EnumField 。
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ("name", "age", "sex", "city")
list_filter =...
从实现方式来说,这是一个继承方法,继承django.db.models.Choices,实现的效果接近枚举类型(Enumeration types)或者字典。
我使用此种方法的目的是,部分不会变动的,带有选项性质的小规模数据,可以不用放在数据库中实现持久化。(这以设计后,修改就要从代码层次进行变动)
Choices有主要2种用法,我这里主要陈述带有models.Choices多继承的类型。
class Level(models.I
color = EnumField ( Color , max_length = 1 )
m = MyModel . objects . filter ( color = Color . RED )
EnumIntegerField工作原理相同,但是基础存储机
For Django3.0+, use models.TextChoices (see docs-v3.0 for enumeration types)
from django.db import models
class MyModel(models.Model):
class Month(models.TextChoices):
JAN = '1', "JANUARY"
FEB = '2', "FEBRUARY"
MAR = '3', "MAR"
choice的主要
使用形式为[(A,B),(C,D),(E,F)]这种形式,对于有一定python了解的同学可能知道python可以采用zip的方式生成。
这里放一个简单例子:
a = ['li', 'zhao', 'dan']
b = ['1', '2', '3']
c = zip(a, b)
print(list(c))
[('li', '1'), ('zhao', '2'), ('dan', '3')]
当然直接用元祖的方式也可以
使用choice
当然,还有更进一步的
使用:
Postgres Array
Field的用法
Django Rest Framework的用法
结合
使用serializers.ModelSerializer和Enum
ChoiceModelSerializerMixin
在不
使用Enum
ChoiceModelSerializerMixin情况下
使用serializers.ModelSerializer
使用serializers.Serializer的子类
序列化PostgreSQL Array
Field
使用Python的enum.auto
choices
用于页面上的选择框标签,需要先提供一个二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容。在浏览器页面上将显示第二个元素的值。例如:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior...
在search_fields中加入一个外键的名字是不能查询的,要写成(外键名__外键中的字段名)的形式.
class HairCutterAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'introduce', 'barbershop']
list_display_links = ['name']
search_...