Django REST框架:如何使字段的详细名称与其field_name不同? [英] Django REST Framework: how to make verbose name of field differ from its field_name?

查看:338
本文介绍了Django REST框架:如何使字段的详细名称与其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 is class and differs from name:

class Tool(models.Model):
    tool_class = jsonfield.JSONField(verbose_name="class")

The Serializer and ViewSet are just stock HyperlinkedModelSerializer and ModelViewSet.

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 a SyntaxError: 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 the Fields 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屋!

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