在 Django 中,如何为 IntegerChoices 枚举定义一个字符串值?
In Django, how do I define a string value for IntegerChoices enum?
我正在使用 Django 3.2 和 Python 3.9。在我的模型中,我定义了一个 int 枚举。我也想为它定义可读的字符串值,所以我尝试了
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0
SELL = 1
labels = {
BUY: 'Buy',
SELL: 'Sell'
}
translation = {v: k for k, v in labels.items()}
但是此定义失败并出现错误
TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'
如何为每个值定义字符串?我不介意字符串是否只是文字变量名称(例如“BUY”、“SELL”)
编辑:针对给出的答案之一,看到这个结果...
>>> t = Transaction.objects.all().first()
>>> t.type
0
>>> str(t.type)
'0'
一种方法是将选择定义为元组中的元组,每个选项都是外部元组的值。
每个内部元组中的第一个元素是要在模型中设置的值,第二个元素是它的字符串 representation.like 下面的代码片段:
class Transaction(models.Model):
BUY = 0
SELL = 1
TRANSACTION_TYPE_CHOICES = (
(BUY, 'Buy'),
(SELL, 'Sell'),
)
type_of_transaction = models.IntegerField(
choices=TRANSACTION_TYPE_CHOICES,
default=BUY,
)
我很欣赏一致的定义,但是这个问题还有其他答案是使用枚举,我认为 Enum 类型是迄今为止最好的。它们可以同时显示项目的整数和字符串,同时让您的代码更多 readable.see 下面的代码片段:
app/enums.py
from enum import Enum
class ChoiceEnum(Enum):
def __str__(self):
return self.name
def __int__(self):
return self.value
@classmethod
def choices(cls):
choices = list()
for item in cls: # Loop thru defined enums
choices.append((item.value, item.name))
return tuple(choices)
class TransactionType(ChoiceEnum):
BUY = 0
SELL = 1
# Uh oh
TransactionType.BUY._name_ = 'Buy'
TransactionType.SELL._name_ = 'Sell'
app/models.py
from django.db import models
from myapp.enums import TransactionType
class Transaction(models.Model):
type_of_transaction = models.IntegerField(choices=TransactionType.choices(), default=int(TransactionType.BUY))
# ...
根据 django official documentation for Django3.2
的更简单方法
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, _('Buy')
SELL = 1, _('Sell')
(或)
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, 'Buy'
SELL = 1, 'Sell'
另一种方法是利用Enum functional api,这个在Django 3.2官方文档中也有提到
TransactionTypes = models.IntegerChoices('TransactionTypes', 'BUY SELL')
TransactionTypes.choices
#provides below output
>>>[(1, 'Buy'), (2, 'Sell')]
编辑:1
考虑到您只有少数交易类型(如 Buy/Sell 和其他未来交易类型的可能性,如 Exchange 或 Return),我建议使用 PositiveSmallIntegerField
适合您的场景。
此处 PositiveSmallIntegerField
支持从 0 到 32767 的值,而 SmallIntegerField
支持从 -32768 到 32767 的值
语法:
models.PositiveSmallIntegerField(**Field Options)
示例:
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, 'Buy'
SELL = 1, 'Sell'
start_transactionType= models.PositiveSmallIntegerField(choices=TransactionTypes.choices, default=TransactionTypes.BUY, help_text="Do you wish to Buy or Sell?", null=True, blank=True, primary_key=False, editable=True)
def __str__(self):
return '%s' % (self.start_transactionType)
__ str __ is a Python method that returns a string representation of any object. This is what Django uses to display model instances as a plain string.
字段选项
choices
: 设置该字段的选项
default
:字段的默认值
help_text
:与表单小部件一起显示的额外“帮助”文本。即使您的字段未在表单上使用,它对文档也很有用
null
:如果设置为True
Django 在数据库中将空值存储为NULL
,默认为False
.
blank
:如果True
,该字段允许为空,默认为False
primary_key
:如果True
,该字段是模型的主键,默认为False
editable
:如果False
,该字段将不会显示在admin或任何其他ModelForm中。在模型验证期间也会跳过它们。默认为 True
.
对于一个实例,您可以按照这个由 5 部分组成的教程系列进行操作,
part 5: Fluent in Django: Get to know Django models better
编辑:2
A number of custom properties are added to the enumeration classes – .choices, .labels, .values, and .names – to make it easier to access lists of those separate parts of the enumeration.
根据 django 文档,可以使用 .label
属性 或 .name
属性
TransactionTypes.BUY.label
>>> “Buy” #returns this output as string value
TransactionType.BUY.name
>>> “BUY” # returns this output
TransactionType.BUY.value
>>> 0 # returns this as output
编辑 3 基于更新的问题和评论
编辑 3 中涵盖的简要信息
- extra instance 方法 example quoted from django 3.2 doc
- 如何将额外实例方法应用到您的用例
- 解决问题的变通函数
Django 3.2 documentation on extra instance method 提及
For every field that has choices set, the object will have a get_FOO_display() method, where FOO is the name of the field. This method returns the “human-readable” value of the field.
Sample example from documentation is given below
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
>>>p = Person(name="Fred Flintstone", shirt_size="L")
>>>p.save()
>>>p.shirt_size
‘L’ #output
>>> p.get_shirt_size_display()
‘Large’ #output
将额外实例方法应用到您的用例
根据您更新的问题和评论,您提到 t
是 Transactions
对象的实例,type
是 PositiveSmallIntegerField
([=45 的实例=]选择)
t.get_type_display() 代码理想情况下应该将输出 Buy
作为字符串
>>> type= models.PositiveSmallIntegersField(choices=TransactionTypes.choices, null=True, blank=True)
>>> t = Transaction.objects.all().first()
>>> t.type
0 #output
>>> t.get_type_display()
‘Buy’ #output
解决方法
一个解决方法是编写一个单独的函数来检查 int 枚举值和 return 标签作为字符串
def label_of_TransactionType:
if (t.type== TransactionType.BUY.value):
return TransactionTypes.BUY.label
else:
return TransactionTypes.SELL.label
我正在使用 Django 3.2 和 Python 3.9。在我的模型中,我定义了一个 int 枚举。我也想为它定义可读的字符串值,所以我尝试了
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0
SELL = 1
labels = {
BUY: 'Buy',
SELL: 'Sell'
}
translation = {v: k for k, v in labels.items()}
但是此定义失败并出现错误
TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'
如何为每个值定义字符串?我不介意字符串是否只是文字变量名称(例如“BUY”、“SELL”)
编辑:针对给出的答案之一,看到这个结果...
>>> t = Transaction.objects.all().first()
>>> t.type
0
>>> str(t.type)
'0'
一种方法是将选择定义为元组中的元组,每个选项都是外部元组的值。 每个内部元组中的第一个元素是要在模型中设置的值,第二个元素是它的字符串 representation.like 下面的代码片段:
class Transaction(models.Model):
BUY = 0
SELL = 1
TRANSACTION_TYPE_CHOICES = (
(BUY, 'Buy'),
(SELL, 'Sell'),
)
type_of_transaction = models.IntegerField(
choices=TRANSACTION_TYPE_CHOICES,
default=BUY,
)
我很欣赏一致的定义,但是这个问题还有其他答案是使用枚举,我认为 Enum 类型是迄今为止最好的。它们可以同时显示项目的整数和字符串,同时让您的代码更多 readable.see 下面的代码片段:
app/enums.py
from enum import Enum
class ChoiceEnum(Enum):
def __str__(self):
return self.name
def __int__(self):
return self.value
@classmethod
def choices(cls):
choices = list()
for item in cls: # Loop thru defined enums
choices.append((item.value, item.name))
return tuple(choices)
class TransactionType(ChoiceEnum):
BUY = 0
SELL = 1
# Uh oh
TransactionType.BUY._name_ = 'Buy'
TransactionType.SELL._name_ = 'Sell'
app/models.py
from django.db import models
from myapp.enums import TransactionType
class Transaction(models.Model):
type_of_transaction = models.IntegerField(choices=TransactionType.choices(), default=int(TransactionType.BUY))
# ...
根据 django official documentation for Django3.2
的更简单方法class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, _('Buy')
SELL = 1, _('Sell')
(或)
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, 'Buy'
SELL = 1, 'Sell'
另一种方法是利用Enum functional api,这个在Django 3.2官方文档中也有提到
TransactionTypes = models.IntegerChoices('TransactionTypes', 'BUY SELL')
TransactionTypes.choices
#provides below output
>>>[(1, 'Buy'), (2, 'Sell')]
编辑:1
考虑到您只有少数交易类型(如 Buy/Sell 和其他未来交易类型的可能性,如 Exchange 或 Return),我建议使用 PositiveSmallIntegerField
适合您的场景。
此处 PositiveSmallIntegerField
支持从 0 到 32767 的值,而 SmallIntegerField
支持从 -32768 到 32767 的值
语法:
models.PositiveSmallIntegerField(**Field Options)
示例:
class Transaction(models.Model):
class TransactionTypes(models.IntegerChoices):
BUY = 0, 'Buy'
SELL = 1, 'Sell'
start_transactionType= models.PositiveSmallIntegerField(choices=TransactionTypes.choices, default=TransactionTypes.BUY, help_text="Do you wish to Buy or Sell?", null=True, blank=True, primary_key=False, editable=True)
def __str__(self):
return '%s' % (self.start_transactionType)
__ str __ is a Python method that returns a string representation of any object. This is what Django uses to display model instances as a plain string.
字段选项
choices
: 设置该字段的选项default
:字段的默认值help_text
:与表单小部件一起显示的额外“帮助”文本。即使您的字段未在表单上使用,它对文档也很有用null
:如果设置为True
Django 在数据库中将空值存储为NULL
,默认为False
.blank
:如果True
,该字段允许为空,默认为False
primary_key
:如果True
,该字段是模型的主键,默认为False
editable
:如果False
,该字段将不会显示在admin或任何其他ModelForm中。在模型验证期间也会跳过它们。默认为True
.
对于一个实例,您可以按照这个由 5 部分组成的教程系列进行操作, part 5: Fluent in Django: Get to know Django models better
编辑:2
A number of custom properties are added to the enumeration classes – .choices, .labels, .values, and .names – to make it easier to access lists of those separate parts of the enumeration.
根据 django 文档,可以使用 .label
属性 或 .name
属性
TransactionTypes.BUY.label
>>> “Buy” #returns this output as string value
TransactionType.BUY.name
>>> “BUY” # returns this output
TransactionType.BUY.value
>>> 0 # returns this as output
编辑 3 基于更新的问题和评论
编辑 3 中涵盖的简要信息
- extra instance 方法 example quoted from django 3.2 doc
- 如何将额外实例方法应用到您的用例
- 解决问题的变通函数
Django 3.2 documentation on extra instance method 提及
For every field that has choices set, the object will have a get_FOO_display() method, where FOO is the name of the field. This method returns the “human-readable” value of the field. Sample example from documentation is given below
from django.db import models class Person(models.Model): SHIRT_SIZES = ( ('S', 'Small'), ('M', 'Medium'), ('L', 'Large'), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
>>>p = Person(name="Fred Flintstone", shirt_size="L") >>>p.save() >>>p.shirt_size ‘L’ #output >>> p.get_shirt_size_display() ‘Large’ #output
将额外实例方法应用到您的用例
根据您更新的问题和评论,您提到 t
是 Transactions
对象的实例,type
是 PositiveSmallIntegerField
([=45 的实例=]选择)
t.get_type_display() 代码理想情况下应该将输出 Buy
作为字符串
>>> type= models.PositiveSmallIntegersField(choices=TransactionTypes.choices, null=True, blank=True)
>>> t = Transaction.objects.all().first()
>>> t.type
0 #output
>>> t.get_type_display()
‘Buy’ #output
解决方法
一个解决方法是编写一个单独的函数来检查 int 枚举值和 return 标签作为字符串
def label_of_TransactionType:
if (t.type== TransactionType.BUY.value):
return TransactionTypes.BUY.label
else:
return TransactionTypes.SELL.label