枚举使用Django ModelField选项作为字符串 - 反模式?

时间:2014-07-10 05:40:03

标签: python django enums

我有一个Django字段,我基本上将其用作通知首选项的枚举。

现在我把它设置成这样:

class MyModel(models.Model):
    # ...
    EVERY_TIME = 'every'; WEEKLY = 'weekly'; NEVER = 'never'
    NOTIFICATION_CHOICES = ((EVERY_TIME, "Every time"), (WEEKLY, "Weekly"), (NEVER, "Never"))
    notification_preferences = models.CharField(choices=NOTIFICATION_CHOICES, default=EVERY_TIME, max_length=10)

我知道通常这种枚举应该设置为models.IntegerField而不是CharField,但由于前端使用Angular,数据全部通过API提供,我感觉它可能会为前端提供更有用的信息,例如接收'weekly'而不是2

使用CharField作为枚举是否被视为不良做法?如果是这样,我的用例是否足够小,这不是什么大问题,或者是否有一些我不知道应该改变它的东西?

5 个答案:

答案 0 :(得分:4)

您可能需要考虑Django-model-utils Choices库,这样可以更好地控制枚举的文本版本。

要回答你的问题,并非所有东西都适用于整数标识符。考虑一下州,澳大利亚有7个,他们在已知集合时有一个固定的:

ACT - Australian Capital Territory
NSW - New South Wales
NT  - Northern Territory
QLD - Queensland
SA  - South Australia
TAS - Tasmania
VIC - Victoria
WA  - Western Australia

由于这些是相对固定的(国家的组成不太可能改变,所以没有理由为每个国家分配一个整数,当文本编码时,全名也可以。

我不会说使用CharField作为选择是反模式,只有在您确定存储时数据库的缩写版本有意义时才应用的方法作为文本。

您也可以使用Enum来存储您的值

from enum import Enum

class Countries(Enum):
   ACT = "Australian Capital Territory"
   NSW = "New South Wales"
   ...

class MyModel(models.Model):
    country = models.CharField(choices=[(tag.name, tag.value) for tag in Countries])

答案 1 :(得分:2)

  

将CharField用作枚举是否被视为不良做法?如果是的话,是   我的用例足够小,不是什么大不了的,或者在那里   我错过了一些我应该改变它的东西?

你正在以完全错误的方式看待这个问题。字段的选择完全取决于您要存储的数据。所以,问题不是CharField对于枚举是不好的做法,你需要问的问题是:

  

"我需要将哪些内容保存在我的数据库中   信息"

如果您希望数据库帮助您对该字段进行计算,那么您应该只在数据库中存储整数,否则,您应该将数字存储为字符串类型,因为这会为您提供更多灵活性。

我不会更深入地研究它,因为它是一个固执己见的主题,我要说的是,如果你决定将数据存储为字符对你的应用程序有意义,那就去做吧。不要在脑海里煮这个。

  

我知道通常这种枚举应该设置为   models.IntegerField而不是CharField,但自前端以来   使用Angular,数据全部通过API提供,我觉得如此   可能会为前端提供更多有用的信息   每周收到一次'而不是2,例如。

我不确定你在哪里得出关于此的结论,但是关于应该枚举的数据类型没有硬性规定。这取决于您的应用程序以及您需要存储的信息 - 并决定 您需要知道如何在数据库中查询此信息。

在您的情况下,您从API可用性角度来看这个,并且完全正常。此模型的主要用途是存储信息,并且应以为应用程序提供最多实用程序的方式存储信息。

最后,不要在Python中使用;。虽然技术上并不正确,但这通常不赞成并且不符合python style guide

答案 2 :(得分:0)

使用CharField作为枚举肯定不再是反模式,考虑到最新的Django文档在its choices example中推荐这种方法,在此重印:

FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
YEAR_IN_SCHOOL_CHOICES = (
    (FRESHMAN, 'Freshman'),
    (SOPHOMORE, 'Sophomore'),
    (JUNIOR, 'Junior'),
    (SENIOR, 'Senior'),
)
year_in_school = models.CharField(max_length=2,
                                  choices=YEAR_IN_SCHOOL_CHOICES,
                                  default=FRESHMAN) 

答案 3 :(得分:0)

答案 4 :(得分:-1)