簡體   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