序列化和取消序列化Django枚举字段以接受数字和文本表示 [英] Serialize and De-serialize a Django Enum field to accept Numerical and Text representation

查看:397
本文介绍了序列化和取消序列化Django枚举字段以接受数字和文本表示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Django中创建一个枚举字段,在GET请求后返回枚举的文本表示,并且POST或PATCH请求将在保存之前将文本表示形式转换为相应的整数。



  transform_< field>()

方法很好地将整数枚举值转换为相应的字符串,但是我无法找出一种更好的方式将字符串转换为除了黑客

  validate_< field>()

p>

有更好的方法吗?请参阅下面的代码



模型文件

  class Status(enum。枚举:
运行= 0
COMPLETED = 1

labels = {
运行:'运行',
COMPLETED:'已完成'
}

translation = {v:k for k,v in labels.iteritems()}

class Job(models.Model):
status = enum .EnumField(Status)

序列化器

 类JobSeralizer(serializers.ModelSerailzer):
status = seralizers.CharField(max_length = 32,default = Status.QUEUED)

def transform_status(self, obj,value):
返回JobStatus.labels [value]

def validate_status(self,attrs,source):
允许状态取数字或字符表示status

status = attrs [source]
如果状态在JobStatus.translation中:
attrs [source] = JobStatus.translatio n [status]
elif status.isdigit():
attrs [source] = int(status)
else:
raise serializers.ValidationError('%s'not a有效状态%状态
返回attrs


解决方案

如OP所述,您可以使用自定义字段在drf v3.x.以下是用于转换值< - >标签(例如枚举值< - >文本表示)的通用自定义字段的快速示例:

  class KeyValueField(serializers.Field):
将字段的值作为键并返回
的字段,用于序列化的相关值

labels = {}
inverted_labels = {}

def __init __(self,labels,* args,** kwargs):
self.labels = labels
#检查以确保标签dict是可逆的,否则
#反序列化可能会产生不可预测的结果
inverted = {}
for k,v in labels.iteritems():
if v
raise ValueError(
'该字段不会与给定的标签反序列化'
'请确保标签映射1:1,值为'

inverted [v] = k
self.inverted_labels = inverted
return super(KeyValueField,self).__ init __(* args,** kwargs)

def to_representation(self,obj):
if type(obj )是列表:
return [self.labels.get(o,None)for o in obj]
else:
return self.labels.get(obj,None)

def to_internal_value(self,data):
if type(data)is list:
return [self.inverted_labels.get(o,None)for o in data]
else :
return self.inverted_labels.get(data,None)

字段初始化将会显示类似这样的:

  class MySerializer(serializers.Serializer):
afield = KeyValueField(labels = {0: enum text 0',1:'enum text 1'})


I'm trying to create an enum field in Django that, upon a GET request will return the text representation of the enum and upon a POST or PATCH request will convert the text representation to the corresponding integer before saving.

The

transform_<field>()

method works nicely for converting the integer enum value to its corresponding string, but I can't figure out a better way of converting the string into it's corresponding integer other than hacking the

validate_<field>()

method.

Is there a better way of doing this? Please see code below

Models file

class Status(enum.Enum):
    RUNNING = 0
    COMPLETED = 1

    labels = {
         RUNNING: 'Running',
         COMPLETED: 'Completed'
    }

    translation = {v: k for k, v in labels.iteritems()}

class Job(models.Model):
    status = enum.EnumField(Status)

Serializer

class JobSeralizer(serializers.ModelSerailzer):
    status = seralizers.CharField(max_length=32, default=Status.QUEUED)

    def transform_status(self, obj, value):
        return JobStatus.labels[value]

    def validate_status(self, attrs, source):
        """Allow status to take numeric or character representation of status
        """
        status = attrs[source]
        if status in JobStatus.translation:
            attrs[source] = JobStatus.translation[status]
        elif status.isdigit():
            attrs[source] = int(status)
        else:
            raise serializers.ValidationError("'%s' not a valid status" % status)
        return attrs

解决方案

As OP stated, you can do this easily using custom fields in drf v3.x. Here's a quick example of a generic custom field used to convert values <-> labels (e.g. enum values <-> textual representation):

class KeyValueField(serializers.Field):
    """ A field that takes a field's value as the key and returns
    the associated value for serialization """

    labels = {}
    inverted_labels = {}

    def __init__(self, labels, *args, **kwargs):
        self.labels = labels
        # Check to make sure the labels dict is reversible, otherwise
        # deserialization may produce unpredictable results
        inverted = {}
        for k, v in labels.iteritems():
            if v in inverted:
                raise ValueError(
                    'The field is not deserializable with the given labels.'
                    ' Please ensure that labels map 1:1 with values'
                )
            inverted[v] = k
        self.inverted_labels = inverted
        return super(KeyValueField, self).__init__(*args, **kwargs)

    def to_representation(self, obj):
        if type(obj) is list:
            return [self.labels.get(o, None) for o in obj]
        else:
            return self.labels.get(obj, None)

    def to_internal_value(self, data):
        if type(data) is list:
            return [self.inverted_labels.get(o, None) for o in data]
        else:
            return self.inverted_labels.get(data, None)

The field initialization would look something like this:

class MySerializer(serializers.Serializer):
    afield = KeyValueField(labels={0:'enum text 0', 1:'enum text 1'})

这篇关于序列化和取消序列化Django枚举字段以接受数字和文本表示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆