tim*_*els 1 django django-models
如何添加额外的数据django.db.models.TextChoices?
class Fruit(models.TextChoices):
APPLE = ('myvalue', True, 'mylabel')
Run Code Online (Sandbox Code Playgroud)
这样:
>>> Fruit.APPLE.is_tasty
True
>>> # And it still works otherwise
>>> Fruit.APPLE.value
'myvalue'
>>> Fruit.APPLE.label
'mylabel'
Run Code Online (Sandbox Code Playgroud)
您需要执行类似于python Enum 文档建议的操作,但与 python 不同Enum,标签已由以下代码处理models.Choices:
class Fruit(models.TextChoices):\n\n APPLE = (\'myvalue\', True, \'mylabel\')\n\n def __new__(cls, value, is_tasty):\n obj = str.__new__(cls, value)\n obj._value_ = value\n obj.is_tasty = is_tasty\n return obj\nRun Code Online (Sandbox Code Playgroud)\n如果您在 上使用它IntegerChoices,您将需要int.__new__. 如果您使用__init__而不是__new__,则枚举值将变为(\'myvalue\', True),它会在您的模型字段中使用Fruit.choices,并且可能不适合您的模型字段。
尽管请注意,当在模型字段上使用选择枚举时,您实际上从未将枚举传递给它,因此它不知道枚举。例如,从它派生的表单字段ModelForm会将它们视为str值,并且在 POST 之后,字段值将是常规值str,而不是枚举值。对于表单情况,您可以定义MyForm.clean_fruit或提供手动表单字段TypedChoiceField(coerce=Fruit),在其他地方您可能需要再次查找枚举值Fruit(value),或者您可以将此混合添加到您的字段中:
class EnumMixin:\n\n \'Convert a DB value back to its Choices value\'\n\n def __init__(self, *args, enum: models.Choices, **kwargs):\n self.__enum = enum\n # it sets choices for you using the enum\n super().__init__(*args, choices=enum.choices, **kwargs)\n\n def deconstruct(self):\n \'Get constructor args to reconstruct this field with later\'\n name, path, args, kwargs = super().deconstruct()\n kwargs[\'enum\'] = self.__enum\n del kwargs[\'choices\']\n return name, path, args, kwargs\n\n def from_db_value(self, value, expression, connection):\n # Convert from db value\n return self.__to_enum(value)\n\n def to_python(self, value):\n \'Called by deserialization and during clean() method used in forms\'\n return self.__to_enum(value)\n\n def __to_enum(self, value):\n if value is None:\n return None\n return self.__enum(value)\n\nclass EnumCharField(EnumMixin, models.CharField):\n pass\n\nclass MyModel(models.Model):\n field = EnumCharField(enum=Fruit, ...)\nRun Code Online (Sandbox Code Playgroud)\ndeconstruct由 django 迁移使用,但请注意,它不会Enum在您进行迁移时重建,它将使用您Enum应用迁移时的任何内容。
虽然super().__new__一般情况下工作得很好,但子类的情况却并非如此Enum(models.TextChoicesis a models.Choices, which is an Enum)。Python 文档注意以下几点:
\n\n该
\n__new__()方法(如果已定义)将在创建 Enum 成员期间使用;然后它被 Enum\xe2\x80\x99s 替换,__new__()该 Enum\xe2\x80\x99s 在类创建后用于查找现有成员。
因此,EnumMeta将 class\' 替换__new__为Enum.__new__on Fruit, TextChoices, ... 如果您调用super().__new__,Fruit.__new__则该调用TextChoices.__new__实际上是Enum.__new__并且不会期望您传递给它的参数(即使它确实接受您的参数,它也不会调用super().__new__自己)。
它将提高:
\nValueError: \'myvalue\' is not a valid Fruit\nRun Code Online (Sandbox Code Playgroud)\n