• A+
所属分类:Django

在Django官方文档中,它们提供了两个关于如何使用预定义选项作为特定字段选择的示例

官方文档的例子

第一个例子中定义choices是用一个元组包裹的元组,里面元组的第一个元素的值是设置在model的值, 第二个元素的值是它的字符串表示。

  1. YEAR_IN_SCHOOL_CHOICES = [
  2.     ('FR', 'Freshman'),
  3.     ('SO', 'Sophomore'),
  4.     ('JR', 'Junior'),
  5.     ('SR', 'Senior'),
  6. ]

另一个例子, 官方建议我们定义选项为model类的常量。

  1. from django.db import models
  2. class Student(models.Model):
  3.     FRESHMAN = 'FR'
  4.     SOPHOMORE = 'SO'
  5.     JUNIOR = 'JR'
  6.     SENIOR = 'SR'
  7.     YEAR_IN_SCHOOL_CHOICES = [
  8.         (FRESHMAN, 'Freshman'),
  9.         (SOPHOMORE, 'Sophomore'),
  10.         (JUNIOR, 'Junior'),
  11.         (SENIOR, 'Senior'),
  12.     ]
  13.     year_in_school = models.CharField(
  14.         max_length=2,
  15.         choices=YEAR_IN_SCHOOL_CHOICES,
  16.         default=FRESHMAN,
  17.     )
  18.     def is_upperclass(self):
  19.         return self.year_in_school in (self.JUNIOR, self.SENIOR)

可以很明显的看出, 第二种方式是开发友好的。

使用枚举

而我在模型中定义字段选择的首选方法是枚举。

什么是枚举

我们先来看官方定义:

An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over.

翻译一下就是:

枚举是一组绑定到唯一常量值的符号名称(成员)。在枚举中,可以通过标识来比较成员,并且可以迭代枚举本身。

定义枚举

下面举一个简单的例子——假设有一个字段来识别一本书的语言,语言的选择是英语,德语,西班牙语和中文。

首先,为这些所有的选项定义一个类:

  1. from enum import Enum
  2. class LanguageChoice(Enum):
  3.     """语言枚举"""
  4.     English = "EN"
  5.     Chinese = "CN"

然后在model里做如下定义:

  1. from django.db import models
  2. class Book(models.Model):
  3.     language = models.CharField(
  4.         max_length=5,
  5.         choices=[(tag.value, tag.name) for tag in LanguageChoice]
  6.     )

CharField字段的choices接收一个可迭代对象,在这个Book模型下,语言的选项是一个由元组构成的列表。为了简单起见,我们用了列表生成式生成我们的列表。

对于选择中的每个元组,第一个元素是存储到模型中的值,而第二个元素是其人类可读的表示。

使用枚举

现在我们已经定义了我们的枚举和模型,我们将如何使用它?假设我们要添加一个语言为'CH'的Book条目:

b = Book(language=LanguageChoice.Chinese.value)
b.save()

为什么要用枚举

可能有人会问:“为什么使用Enum而不是Django官方文档中给出的示例?”

预定义值在内存中,Enumeration可用于整个程序,而不仅仅是模型中。这样相对来说对人类更加友好,并且如果某一相对应的值有变化时,并不需要更改代码。

什么时候使用Enum?

根据PEP435,枚举对于定义可能具有或不具有语义含义的不可变的,相关的常量值集合是有用的。
例如:错误状态值和定义过程中的状态。

更优雅的代码

上述的使用方法看起来还是有点奇怪,在我们定义model的时候不得不手动写一个循环。事实上只需要重载枚举类的__iter__即可满足django对choice的可迭代要求。

  1. from enum import Enum, EnumMeta
  2. class ChoiceEnumMeta(EnumMeta):
  3.     def __iter__(self):
  4.         return ((tag.value, tag.name) for tag in super().__iter__())
  5. class ChoiceEnum(Enum, metaclass=ChoiceEnumMeta):
  6.     """
  7.     Enum for Django ChoiceField use.
  8.     """
  9.     pass

样例

  1. class MyModel(models.Model):
  2.     class Languages(ChoiceEnum):
  3.         Chinese = "ch"
  4.         English = "en"
  5.         French = "fr"
  6.     language = models.CharField(max_length=20, choices=Languages)

它等价于

  1. class MyModel(models.Model):
  2.     Languages = (
  3.         ("ch", "Chinese")
  4.         ("en", "English")
  5.         ("fr", "French")
  6.     )
  7.     language = models.CharField(max_length=20, choices=Languages)

 

原文来源于:https://abersheeran.com/articles/Django-Model-CharField-Choice/

更多Django深度开发教程请访问:https://abersheeran.com/

李金龙

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: