在Django中,如何为IntegerChoices枚举定义字符串值



我使用的是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:如果设置为TrueDjango在数据库中将空值存储为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

额外实例方法应用于用例

根据您更新的问题&您提到tTransactions对象的实例,typePositiveSmallIntegerField(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,
)

最新更新