Django REST框架:如何使字段的详细名称与其field_name不同? [英] Django REST Framework: how to make verbose name of field differ from its field_name?
问题描述
我有一个包含字段 tool_class
的模型,其详细名称为 class
,与名称不同:
$ b
类工具(models.Model):
tool_class = jsonfield.JSONField(verbose_name =class)
Serializer和ViewSet只是库存 HyperlinkedModelSerializer
和 ModelViewSet
。
所以,当我用一个键$ code> ,被认定为罚款:
'{class:...}
但在响应数据中,它被称为 tool_class
再次:
{tool_class:...}
pre>
如何使它被称为
class
永远?
我不能使用名称
class
作为字段名称,因为它是python中的保留字,但在API中绝对必须称为class
,因为API符合一个cer
显然,我不能说:
class = CharField(source =tool_class)
在我的
ToolSerializer
,因为它是一个SyntaxError:无效语法
。
简单解决方案:
另一个线程中的人建议一个很好的解决方案。您可以使用vars()
语法来规避此问题。例如,我使用以下代码:类工具(文档):
vars()['class' ] = mongoengine.fields.DictField(required = True)
串行器自动创建相应的字段。不是我们鬼祟吗?
解决方案您可以通过覆盖Serializer的元类来实现。以下是一个
serializers.py
文件的示例。
主要的魔法是元类的这一部分
#重映射字段(使用类而不是class_)
fields_ = []
用于名称,字段字段:
如果name.endswith('_'):
name = name.rstrip('_')
fields_.append((name,field))
这个任何你在序列化器中定义的字段以一个下划线结尾(即
field _
),并在绑定Fields
并在_declared_fields
属性时,从名称中删除下划线串行器。从集合导入OrderedDict
from rest_framework import serializers
from rest_framework.fields import Field
from snippets.models import Snippet,LANGUAGE_CHOICES,STYLE_CHOICES
class MyMeta(serializers.SerializerMetaclass):
@classmethod
def _get_declared_fields(cls,bases ,attrs):
fields = [(field_name,attrs.pop(field_name))
for field_name,obj in list(attrs.items())
if isinstance(obj,Field)]
fields.sort(key = lambda x:x [1] ._ creation_counter)
#如果此类子类化另一个Serializer,请添加该Serializer的
#字段。请注意,我们循环在* reverse *的基础上。为了保持正确的字段顺序,这是必要的
#。
为基数(基数):
如果hasattr(base,'_declared_fields'):
fields = list(base._declared_fields.items())+字段
#重映射字段(使用类而不是class_)
fields_ = []
用于名称,字段中的字段:
如果name.endswith('_'):
name = name.rstrip('_')
fields_.append((name,field))
返回OrderedDict(fields_)
类ToolSerializer(serializers.Serializer):
__metaclass__ = MyMeta
...
class_ = serializers.JSONField(source ='tool_class',label ='class' )
def create(self,validated_data):
创建并返回一个新的Snippet实例,给出验证的数据
return Snippet.objects.create(** validated_data)
def update(self,instance,validated_data):
给定验证的数据,更新并返回现有的Snippet实例。
...
instance.class_ = validated_data.get('class',instance.class_)
instance.save()
return instance
I've got a model with a field
tool_class
, whose verbose name isclass
and differs from name:class Tool(models.Model): tool_class = jsonfield.JSONField(verbose_name="class")
The Serializer and ViewSet are just stock
HyperlinkedModelSerializer
andModelViewSet
.So, when I POST or PUT data to the server with a key
class
, it is recognized fine:'{"class": "..."}
but in the response data it is called
tool_class
again:{"tool_class": "..."}
How to make it be called
class
always?I can't use the name
"class"
for the field name, as it is a reserved word in python, but in API it absolutely must be called"class"
, because the API conforms to a certain open standard, which specifies this word.Obviously, I cannot say:
class = CharField(source="tool_class")
in my
ToolSerializer
, because it's aSyntaxError: invalid syntax
.
SIMPLE SOLUTION: Guys in another thread suggested a great solution. You can use
vars()
syntax to circumvent this problem. For instance, I use the following code:class Tool(Document): vars()['class'] = mongoengine.fields.DictField(required=True)
Serializer creates respective field automatically. Ain't we sneaky?
解决方案You can do this by overriding the metaclass for Serializers. Here is an example of a
serializers.py
file.The main magic is this section of the metaclass
# Remap fields (to use class instead of class_) fields_ = [] for name, field in fields: if name.endswith('_'): name = name.rstrip('_') fields_.append((name, field))
This takes any field you define in the serializer that ends in an underscore (ie.
field_
) and removes the underscore from the name when it binds theFields
and sets the_declared_fields
attribute on the serializer.from collections import OrderedDict from rest_framework import serializers from rest_framework.fields import Field from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES class MyMeta(serializers.SerializerMetaclass): @classmethod def _get_declared_fields(cls, bases, attrs): fields = [(field_name, attrs.pop(field_name)) for field_name, obj in list(attrs.items()) if isinstance(obj, Field)] fields.sort(key=lambda x: x[1]._creation_counter) # If this class is subclassing another Serializer, add that Serializer's # fields. Note that we loop over the bases in *reverse*. This is necessary # in order to maintain the correct order of fields. for base in reversed(bases): if hasattr(base, '_declared_fields'): fields = list(base._declared_fields.items()) + fields # Remap fields (to use class instead of class_) fields_ = [] for name, field in fields: if name.endswith('_'): name = name.rstrip('_') fields_.append((name, field)) return OrderedDict(fields_) class ToolSerializer(serializers.Serializer): __metaclass__ = MyMeta ... class_ = serializers.JSONField(source='tool_class', label='class') def create(self, validated_data): """ Create and return a new `Snippet` instance, given the validated data. """ return Snippet.objects.create(**validated_data) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ ... instance.class_ = validated_data.get('class', instance.class_) instance.save() return instance
这篇关于Django REST框架:如何使字段的详细名称与其field_name不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!