python - 自定义 Django 字段不从查询返回 Enum 实例

标签 python django python-3.x enums django-custom-field

我实现了一个简单的自定义字段来利用 Python 3 Enum 实例。将枚举实例分配给我的模型属性并保存到数据库工作正常。但是,使用 QuerySet 获取模型实例会导致枚举属性成为字符串,而不是相应的枚举实例。

如何让下面的 EnumField 返回有效的 Enum 实例,而不是字符串?

字段.py:

from enum import Enum

from django.core.exceptions import ValidationError
from django.db import models


class EnumField(models.CharField):
    description = 'Enum with strictly typed choices'

    def __init__(self, enum_class, *args, **kwargs):
        self._enum_class = enum_class
        choices = []
        for enum in self._enum_class:
            title_case = enum.name.replace('_', ' ').title()
            entry = (enum, title_case)
            choices.append(entry)
        kwargs['choices'] = choices
        kwargs['blank'] = False  # blank doesn't make sense for enum's
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        args.insert(0, self._enum_class)
        del kwargs['choices']
        return name, path, args, kwargs

    def from_db_values(self, value, expression, connection, context):
        return self.to_python(value)

    def to_python(self, value):
        if value is None or isinstance(value, self._enum_class):
            return value
        else:
            return self._parse_enum(value)

    def _parse_enum(self, value):
        try:
            enum = self._enum_class[value]
        except KeyError:
            raise ValidationError("Invalid type '{}' for {}".format(
                value, self._enum_class))
        else:
            return enum

    def get_prep_value(self, value):
        if value is None:
            return None
        elif isinstance(value, Enum):
            return value.name
        else:
            msg = "'{}' must have type {}".format(
                value, self._enum_class.__name__)
            if self.null:
                msg += ', or `None`'
            raise TypeError(msg)

    def get_choices(self, **kwargs):
        kwargs['include_blank'] = False  # Blank is not a valid option
        choices = super().get_choices(**kwargs)
        return choices

最佳答案

经过大量挖掘,我能够回答我自己的问题:

SubfieldBase 已被弃用,并将在 Django 1.10 中删除;这就是为什么我将其排除在上面的实现之外。不过,看来它所做的事情还是很重要的。添加以下方法来替换 SubfieldBase 本应添加的功能。

def contribute_to_class(self, cls, name, **kwargs):
    super(EnumField, self).contribute_to_class(cls, name, **kwargs)
    setattr(cls, self.name, Creator(self))

Creator 描述符是对属性调用 to_python 的。如果没有发生这种情况,对模型的查询将导致模型实例中的 EnumField 字段只是字符串,而不是我想要的 Enum 实例。

关于python - 自定义 Django 字段不从查询返回 Enum 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34912460/

相关文章:

python - 如何在两个项目中使用一个 Django 应用程序(带有一个数据库)? (使用我的应用程序作为服务)

python - Keras CNN,详细的训练进度条显示

python - 如何将 JSON 对象从 Perl 发送到 Python?

python - 无法在 Ubuntu 16.04(64 位)上安装 Snap7 库

python - 将 django 应用程序从免费扩展到基本应用程序服务时出现运行时错误

django - Satchless著名的优秀文档在哪里?

python - 在 python 中使用 if 语句有条件地增加整数计数

python - AttributeError: 'pygame.math.Vector2' 对象没有属性

python - 从数据库中检索数据并设置为 Kivy 中的文本输入字段和图像小部件,用于多屏应用程序!属性错误

python - 循环打印 Python Windows