如何在 Django REST 框架中更改字段名称

Posted

技术标签:

【中文标题】如何在 Django REST 框架中更改字段名称【英文标题】:How to change field name in Django REST Framework 【发布时间】:2014-05-22 09:21:44 【问题描述】:

我正在尝试更改 DRF 序列化程序中的模型字段名称,如 SQL 中的别名。我尝试了不同的方法,但都没有成功。

models.py

class Park(models.Model):
    name = models.CharField(max_length=256)
    alternate_name = models.CharField(max_length=256, blank=True)
    objects = models.GeoManager()

    class Meta:
        db_table = u'p_park'

    def __unicode__(self):
        return '%s' % self.name

    def alias_alternate_name(self):
        return self.alternate_name

serializers.py

class ParkSerializer(serializers.ModelSerializer):

    location = serializers.Field(source='alias_alternate_name')
    #location = serializers.SerializerMethodField(source='alias_alternate_name')

    #alternate_name as location


    class Meta:
        model = Park
        fields = ('id', 'name', 'location')

我也尝试在 Django Queryset 中添加别名,但无法更改。

更新

这是我面临的例外

/ViewName/ 'module' 对象的 AttributeError 没有属性 'Field'

我该怎么做?

【问题讨论】:

您是否使用了serializers.SerializerMethodField 方法的正确实现?我的意思是:serializers.SerializerMethodField('get_location')def get_location(self, obj): ... 我们能看到serializers.py的导入吗? 将对问题投反对票,因为 OP 接受了部分错误且令人困惑的答案,而不是下面更好的答案... 【参考方案1】:

另一种方法

class UrlHyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
    field_name_map = 

    def to_representation(self, instance):
        res = super().to_representation(instance)
        nres = res.__class__()
        for k, v in res.items():
            nres[self.field_name_map.get(k, k)] = v
        return nres

class CommentSerializer(UrlHyperlinkedModelSerializer):
    field_name_map = 
        'a': 'a_url'
    

    class Meta:
        model = models.Comment
        fields = ['a', 'url', 'body', 'created_at']

【讨论】:

【参考方案2】:

序列化器字段和序列化器有一个非常好的功能,通常称为“源”,您可以在其中指定模型字段的数据源。

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.SomeSerializerField(source='alternate_name')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

其中 serializers.SomeSerializerField 可以是您的模型所建议的 serializers.CharField,但也可以是任何其他字段。此外,您可以改为放置关系字段和其他序列化程序,这仍然会像魅力一样工作。即即使alternate_name 是另一个模型的外键字段。

class ParkSerializer(serializers.ModelSerializer):
    locations = AlternateNameSerializer(source='alternate_name', many=true)

    class Meta:
        model = Park
        fields = ('other_fields', 'locations')

class AlternateNameSerializer(serializers.ModelSerialzer):
    class Meta:
        model = SomeModel

这也适用于创建、删除和修改请求。它有效地创建了序列化程序中的字段名称和模型中的字段名称的一对一映射。

【讨论】:

我同意,source 是更通用的方法。但是您可以在问题中看到很少有人尝试使用它,因此如果您想以这种方式回答,您还应该弄清楚为什么原始代码不起作用,不是吗? 你的代码可以正常工作..只要请求是列表和检索 两个答案都不完整。在外键的情况下,这个方法意味着当创建一个新的 Park 时,你必须在你的 POST 请求中将整个父对象(alternate_name)作为一个字典,这很疯狂,因为父对象已经存在。应该能够通过其 id 提及外部实例。 就我而言(外键),我用locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()) 解决了这个问题。显然RelatedField也可以使用。 @chefarov source='new_name' 是一个通用参数,您可以将其提供给序列化器字段、关系和其他相关序列化器等。不知道您为什么说答案不完整。【参考方案3】:

我知道这是将近 2 年后的事了,但我认为这可能对任何未来的开发者都有帮助...

代码不起作用的原因是 models.pylocation = serializers.Field(source='alias_alternate_name') 中的以下行 这就是异常试图告诉我们的。即:AttributeError at /ViewName/ 'module' object has no attribute 'Field' 表示 serializers 模块没有名为 Field 的项目。

我想提供与其他答案不同的解决方案: 修改 models.py 以包含 related_name 字段,然后在序列化程序中简单地使用此名称。

这种方法的优点是序列化程序中的字段名称和模型中的字段名称的一对一映射代码较少,缺点是这种方法可能不适用于复杂的外键关系。

这是我的方法的演示:

models.py

class Park(models.Model):
    name = models.CharField(max_length=256)
    alternate_name = models.CharField(max_length=256, blank=True, related_name='location')
    objects = models.GeoManager()

    class Meta:
        db_table = u'p_park'

serializers.py

class ParkSerializer(serializers.ModelSerializer):

    class Meta:
        model = Park
        fields = ('id', 'name', 'location')

在此处了解更多信息: https://www.django-rest-framework.org/api-guide/relations/

【讨论】:

【参考方案4】:

你可以使用serializers.SerializerMethodField:

这是模型 Park,其中包含 name 和 alternate_name 字段。

class Park(models.Model):
    name = models.CharField(max_length=256)
    alternate_name = models.CharField(max_length=256, blank=True)
    objects = models.GeoManager()

    class Meta:
        db_table = u'p_park'

    def __unicode__(self):
        return '%s' % self.name

这里是 Park 模型的 Serializer,ParkSerializer。这会将alternate_name 的名称更改为位置。

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.SerializerMethodField('get_alternate_name')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

    def get_alternate_name(self, obj):
        return obj.alternate_name

此外,您可以将serializers.CharFieldsource 属性一起使用:

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.CharField(source='other_fields')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

Django 用于遍历外键的__ 表示法也可以:

location = serializers.CharField(source='OtherModel__other_fields')

如果您想更改 API 上的返回类型,同样的原则也适用,因此您也可以更改 serializers.DecimalField(source=...) 和其他字段类型。

但这仅适用于只读字段。

【讨论】:

现在这个异常在/ViewName/'module'对象没有属性'SerializerMethodField'抛出AttributeError 如何通过创建和编辑请求进行锻炼? 'Zen of Python' 第 13 行:“应该有一种——最好只有一种——明显的方法。” 这不应该是公认的答案。请参阅下面的那个,在我写这篇文章的时候,它的赞成票几乎是我的 5 倍。 这是一个糟糕的解决方案。请改用source kwarg,如下所述。【参考方案5】:

这也适用于写操作

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.CharField(source='alternate_name')

    class Meta:
        model = Park
        fields = ('id', 'name', 'location')

【讨论】:

以上是关于如何在 Django REST 框架中更改字段名称的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest 框架,如何在 ModelSerializer 中包含“__all__”字段和相关字段?

如何在 django rest 框架中定义列表字段?

如何在 django rest 框架 ModelSerializer 中覆盖模型字段验证

django rest框架返回视图中的选定字段

如何在 django rest 框架中为枚举字段创建序列化程序

如何在 Django REST 框架中为多对多字段定义“IsOwner”自定义权限?