繁体   English   中英

使用 Django ModelField 选择作为字符串的枚举 — 反模式?

[英]Enum using Django ModelField choices as string — anti-pattern?

我有一个 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作为枚举是否被认为是不好的做法? 如果是这样,我的用例是否足够小以至于没什么大不了的,还是我遗漏了什么我应该改变它?

您可能需要考虑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])

使用 CharField 作为枚举是否被认为是不好的做法? 如果是这样,我的用例是否足够小以至于没什么大不了的,还是我遗漏了什么我应该改变它?

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

“对于这条信息,我需要在我的数据库中存储什么?”

有一种观点认为,如果您希望数据库帮助您对该字段进行计算,您应该只将整数存储在数据库中,否则,您应该将数字存储为字符串类型,因为这为您提供了更大的灵活性。

我不会更深入地讨论这个问题,因为这是一个固执己见的话题,我要说的是,如果您认为将数据存储为字符对您的应用程序有意义,那么就去做吧。 不要在你的脑海中过度烹饪。

我知道一般这种枚举应该设置为models.IntegerField而不是CharField,但是由于前端使用Angular并且数据都是通过API提供的,我觉得它可能会提供一些更有用的例如,前端接收“每周”而不是 2 的信息。

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

就您而言,您是从 API 可用性的角度来看这一点的,这很好 此模型的主要目的是存储信息,并且该信息的存储方式应为您的应用程序提供最大效用。

最后,不要使用; 在 Python 中。 虽然技术上没有错误,但这通常是不受欢迎的,并且不符合python 风格指南

对枚举使用CharField绝对不再是反模式,考虑到最新的 Django 文档在它的choices示例中推荐了这种方法,重印在这里:

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) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM