序列化和取消序列化Django枚举字段以接受数字和文本表示

编程入门 行业动态 更新时间:2024-10-27 01:29:37
本文介绍了序列化和取消序列化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枚举字段以接受数字和文本表示

本文发布于:2023-11-11 06:35:58,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1577651.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列化   字段   文本   数字   Django

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!