我使用的是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'
根据Django3.2 的django官方文档,这是一种更简单的方法
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函数api,Django 3.2官方文档中也提到了这一点
TransactionTypes = models.IntegerChoices('TransactionTypes', 'BUY SELL')
TransactionTypes.choices
#provides below output
>>>[(1, 'Buy'), (2, 'Sell')]
编辑:1
考虑到你只有少数交易类型(如买入/卖出和其他未来交易类型的可能性,如交换或退货(,我建议使用更适合你的场景的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__是一个Python方法,它返回任何对象的字符串表示。这就是Django用来将模型实例显示为纯字符串的方法。
字段选项
choices
:设置此字段的选项default
:字段的默认值help_text
:要与表单小部件一起显示的额外"帮助"文本。即使您的字段未在表单中使用,它对文档也很有用null
:如果设置为True
Django在数据库中将空值存储为NULL
,则默认为False
blank
:如果True
,则允许此字段为空,默认情况下其False
primary_key
:如果True
,则此字段是模型的主键,默认情况下为False
editable
:如果False
,则该字段将不会显示在管理员或任何其他ModelForm中。在模型验证过程中也会跳过它们。默认值为True
对于一个实际的示例,您可以按照这个由5部分组成的系列教程进行操作,第5部分:精通Django:更好地了解Django模型
编辑:2
许多自定义属性被添加到枚举类中,如.coptions、.labels、.values和.names,以便于访问枚举中这些独立部分的列表。
根据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 中包含的简要信息
- 引用自django 3.2文档的额外实例方法示例
- 如何将额外实例方法应用于您的用例
- 解决问题的变通办法功能
Django 3.2关于额外实例方法的文档提到
对于每个设置了选项的字段,对象将有一个get_FOO_display((方法,其中FOO是字段的名称。此方法返回字段的"人类可读"值。下面给出了文档中的示例
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
(TransactionTypes
选项的实例(的注释
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枚举值进行检查,并将标签返回为字符串
def label_of_TransactionType:
if (t.type== TransactionType.BUY.value):
return TransactionTypes.BUY.label
else:
return TransactionTypes.SELL.label
我很欣赏一致的定义,但这个问题还有其他答案是使用枚举,我认为枚举类型是迄今为止最好的。它们可以同时显示一个项目的整数和字符串,同时保持代码的可读性。请参阅下面的代码片段:
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))
# ...
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,
)