Python Django:如何创建类的枚举来定义选择
如何对模型进行子类化。定义类枚举的选项 以下代码引发TypeError:Python Django:如何创建类的枚举来定义选择,python,django,enums,Python,Django,Enums,如何对模型进行子类化。定义类枚举的选项 以下代码引发TypeError: from django.db.models import Choices class DataTypes(type, Choices): CHAR = str, _('Short string') INTEGER = int, _('Integer') 错误消息: dynamic_attributes = {k for c in enum_class.mro() TypeError: descripto
from django.db.models import Choices
class DataTypes(type, Choices):
CHAR = str, _('Short string')
INTEGER = int, _('Integer')
错误消息:
dynamic_attributes = {k for c in enum_class.mro()
TypeError: descriptor 'mro' of 'type' object needs an argument
更新:
如果未使用mixin,则不会出现错误。但同样,成员的值没有正确转换为所需的数据类型
class DataTypes(Choices):
CHAR = str, _('Short string')
INTEGER = int, _('Integer')
测试:
我同意威廉·范昂森在评论中的观点。我认为不可能为类这样的数据类型使用
模型。因此,我试图找到一种能够扩展其他类的不同方法
还实现了为选项定义标签(正如Django choices所做的那样)
def _is_dunder(name):
"""
Stolen liberally from 'aenum'.
Returns True if a __dunder__ name, False otherwise.
"""
return (len(name) > 4 and
name[:2] == name[-2:] == '__' and
name[2] != '_' and
name[-3] != '_')
class ChoicesMeta(type):
def __new__(mcs, cls, bases, attrs):
# ignore any keys listed in _ignore_
ignore = attrs.setdefault('_ignore_', [])
ignore.append('_ignore_')
# save constant names into list.
names = [k for k in attrs if not(_is_dunder(k) or k in ignore)]
# save constant labels into list.
labels = []
for k in names:
value = attrs[k]
if (
isinstance(value, (list, tuple)) and
len(value) > 1 and
isinstance(value[-1], (Promise, str))
):
value, label = value
else:
label = k.replace('_', ' ').title()
labels.append(label)
attrs[k] = value
new_cls = super().__new__(mcs, cls, bases, attrs)
new_cls.local_names = names
new_cls.local_labels = labels
return new_cls
@property
def names(cls):
names = []
for c in reversed(cls.__mro__):
names.extend(getattr(c, 'local_names', []))
return list(dict.fromkeys(names))
@property
def choices(cls):
empty = [(None, cls.__empty__)] if hasattr(cls, '__empty__') else []
return empty + [(getattr(cls, name), cls.labels[i]) for i, name in enumerate(cls.names)]
@property
def labels(cls):
labels = []
for c in reversed(cls.__mro__):
labels.extend(getattr(c, 'local_labels', []))
return list(dict.fromkeys(labels))
class Choices(metaclass=ChoicesMeta):
pass
现在,您可以创建Choices类并将其子类化:
class DataTypes(Choices):
CHAR = str, _('Short string')
INTEGER = int
class OtherTypes(DataTypes):
BOOLEAN = bool, _('Boolean (Either True or False)')
FLOAT = float, _('Floating point number')
测试:
str in (DataTypes.CHAR, DataTypes.INTEGER) # True
bool in (OtherTypes.CHAR, OtherTypes.BOOLEAN) # True
DataTypes.choices # [(<class 'str'>, 'Short string'), (<class 'int'>, 'Integer')]
OtherTypes.choices # [(<class 'str'>, 'Short string'), (<class 'int'>, 'Integer'), (<class 'bool'>, 'Boolean (Either True or False)'), (<class 'float'>, 'Floating point number')]
str-in(DataTypes.CHAR,DataTypes.INTEGER)#True
bool in(OtherTypes.CHAR,OtherTypes.BOOLEAN)#True
DataTypes.choices#[(,'Short string'),(,'Integer')]
OtherTypes.choices#[(,'Short string'),(,'Integer'),(,'Boolean(True或False)”,(,'Floating point number')]
我同意威廉·范昂森在评论中的观点。我认为不可能为类这样的数据类型使用模型。因此,我试图找到一种能够扩展其他类的不同方法
还实现了为选项定义标签(正如Django choices所做的那样)
def _is_dunder(name):
"""
Stolen liberally from 'aenum'.
Returns True if a __dunder__ name, False otherwise.
"""
return (len(name) > 4 and
name[:2] == name[-2:] == '__' and
name[2] != '_' and
name[-3] != '_')
class ChoicesMeta(type):
def __new__(mcs, cls, bases, attrs):
# ignore any keys listed in _ignore_
ignore = attrs.setdefault('_ignore_', [])
ignore.append('_ignore_')
# save constant names into list.
names = [k for k in attrs if not(_is_dunder(k) or k in ignore)]
# save constant labels into list.
labels = []
for k in names:
value = attrs[k]
if (
isinstance(value, (list, tuple)) and
len(value) > 1 and
isinstance(value[-1], (Promise, str))
):
value, label = value
else:
label = k.replace('_', ' ').title()
labels.append(label)
attrs[k] = value
new_cls = super().__new__(mcs, cls, bases, attrs)
new_cls.local_names = names
new_cls.local_labels = labels
return new_cls
@property
def names(cls):
names = []
for c in reversed(cls.__mro__):
names.extend(getattr(c, 'local_names', []))
return list(dict.fromkeys(names))
@property
def choices(cls):
empty = [(None, cls.__empty__)] if hasattr(cls, '__empty__') else []
return empty + [(getattr(cls, name), cls.labels[i]) for i, name in enumerate(cls.names)]
@property
def labels(cls):
labels = []
for c in reversed(cls.__mro__):
labels.extend(getattr(c, 'local_labels', []))
return list(dict.fromkeys(labels))
class Choices(metaclass=ChoicesMeta):
pass
现在,您可以创建Choices类并将其子类化:
class DataTypes(Choices):
CHAR = str, _('Short string')
INTEGER = int
class OtherTypes(DataTypes):
BOOLEAN = bool, _('Boolean (Either True or False)')
FLOAT = float, _('Floating point number')
测试:
str in (DataTypes.CHAR, DataTypes.INTEGER) # True
bool in (OtherTypes.CHAR, OtherTypes.BOOLEAN) # True
DataTypes.choices # [(<class 'str'>, 'Short string'), (<class 'int'>, 'Integer')]
OtherTypes.choices # [(<class 'str'>, 'Short string'), (<class 'int'>, 'Integer'), (<class 'bool'>, 'Boolean (Either True or False)'), (<class 'float'>, 'Floating point number')]
str-in(DataTypes.CHAR,DataTypes.INTEGER)#True
bool in(OtherTypes.CHAR,OtherTypes.BOOLEAN)#True
DataTypes.choices#[(,'Short string'),(,'Integer')]
OtherTypes.choices#[(,'Short string'),(,'Integer'),(,'Boolean(True或False)”,(,'Floating point number')]
您使用的是什么Django版本?我使用的是Django 3.1这是Enum
类本身的结果:新的Enum类必须有一个基本Enum类,最多一个具体的数据类型。()。我建议只使用选项
,因此不要键入它。对于对象
它也不起作用。您使用的是什么Django版本?我使用的是Django 3.1这是枚举
类本身的结果:新的枚举类必须有一个基本枚举类,最多一个具体数据类型。()。我建议只使用选项
,因此不要键入它。对于对象
,它也不起作用。