如何在 Django 模型中使用枚举作为选择字段

新手上路,请多包涵

我有一个模型类,我希望其中的两个字段成为一个选择字段,因此为了填充这些选择,我正在使用下面列出的枚举

#models.py
class Transaction(models.Model):
    trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
    transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())

#enums.py
class TransactionType(Enum):

    IN = "IN",
    OUT = "OUT"

    @classmethod
    def choices(cls):
        print(tuple((i.name, i.value) for i in cls))
        return tuple((i.name, i.value) for i in cls)

class TransactionStatus(Enum):

    INITIATED = "INITIATED",
    PENDING = "PENDING",
    COMPLETED = "COMPLETED",
    FAILED = "FAILED"
    ERROR = "ERROR"

    @classmethod
    def choices(cls):
        print(tuple((i.name, i.value) for i in cls))
        return tuple((i.name, i.value) for i in cls)

但是,当我尝试通过管理员访问此模型时,出现以下错误:

 Django Version: 1.11
Exception Type: ValueError
Exception Value:
too many values to unpack (expected 2)

我关注了两篇描述如何使用枚举的文章:

原文由 Paras 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

您的代码中的问题是 INITIATED = "INITIATED", INITIATED 选项和其他选项之后的逗号。当我们在任何字符串后添加逗号时,它将成为一个元组。请参阅下面的示例

s = 'my str'
print(type(s))
# output: str

s = 'my str',
print(type(s))
# output: tuple

#models.py

 class Transaction(models.Model):
    trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
    transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())

#enums.py

 class TransactionType(Enum):

    IN = "IN"
    OUT = "OUT"

    @classmethod
    def choices(cls):
        print(tuple((i.name, i.value) for i in cls))
        return tuple((i.name, i.value) for i in cls)

class TransactionStatus(Enum):

    INITIATED = "INITIATED"
    PENDING = "PENDING"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    ERROR = "ERROR"

    @classmethod
    def choices(cls):
        print(tuple((i.name, i.value) for i in cls))
        return tuple((i.name, i.value) for i in cls)

对于 django > 3.0 https://docs.djangoproject.com/en/4.0/ref/models/fields/#field-choices-enum-types

原文由 anjaneyulubatta505 发布,翻译遵循 CC BY-SA 4.0 许可协议

Django 3.0 内置了对枚举的支持

例子:

>  from django.utils.translation import gettext_lazy as _
>
> class Student(models.Model):
>
>     class YearInSchool(models.TextChoices):
>         FRESHMAN = 'FR', _('Freshman')
>         SOPHOMORE = 'SO', _('Sophomore')
>         JUNIOR = 'JR', _('Junior')
>         SENIOR = 'SR', _('Senior')
>         GRADUATE = 'GR', _('Graduate')
>
>     year_in_school = models.CharField(
>         max_length=2,
>         choices=YearInSchool.choices,
>         default=YearInSchool.FRESHMAN,
>     )
>
> ```
>
> 这些工作类似于 Python 标准库中的 [枚举](https://docs.python.org/3/library/enum.html#module-enum),但有一些修改:
>
> - 枚举成员值是构造具体数据类型时要使用的参数元组。 Django 支持在此元组的末尾添加一个额外的字符串值以用作人类可读的名称,或 `label` 。 `label` 可以是惰性可翻译字符串。因此,在大多数情况下,成员值将是 `(value, label)` 二元组。如果未提供元组,或者最后一项不是(惰性)字符串,则会根据成员名称 [自动生成](https://docs.djangoproject.com/en/stable/ref/models/fields/#field-choices-enum-auto-label) 标签。
> - `.label` 属性被添加到值上,以返回人类可读的名称。 A number of custom properties are added to the enumeration classes – `.choices` , `.labels` , `.values` , and `.names` – to make it easier to枚举的那些单独部分的访问列表。使用 `.choices` 作为合适的值传递给字段定义中的选择。
> - 强制使用 [`enum.unique()`](https://docs.python.org/3/library/enum.html#enum.unique) 以确保不能多次定义值。这不太可能出现在一个领域的选择中。

有关更多信息, [请查看文档](https://docs.djangoproject.com/en/stable/ref/models/fields/#field-choices-enum-types)

## 笔记:

正如@Danielle Madeley 指出的那样,如果您尝试直接访问 `year_in_school` 属性,Django 仍然返回原始字符串而不是 Enum 对象:

student.year_in_school ‘FR’


我通常做的是创建一个返回 Enum 对象的辅助方法:

class Student(models.Model): …

def get_year_in_school(self) -> YearInSchool:
    # Get value from choices enum
    return self.YearInSchool[self.year_in_school]

”`

原文由 Cesar Canassa 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏