重写DRF的to_representation和to_internal_value方法有什么用途?

DRF所有序列化器类都继承了BaseSerializer 类, 通过重写该类的 to_representation()to_internal_value()方法可以改变序列化和反序列化的行为,比如给序列化后的数据添加额外的数据,或者对客户端API请求携带的数据进行反序列化处理以及用来自定义序列化器字段。

  1. to_representation() 允许我们改变序列化的输出。

  2. to_internal_value() 允许改变我们反序列化的输出。

那么这两个方法该如何使用呢? 小编我今天就带你看一看!

假设我们有如下一个文章模型(Article):

from django.contrib.auth.models import User
from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=256)
    body = models.TextField()
    liked_by = models.ManyToManyField(to=User)


    def __str__(self):
        return self.title

每个文章资源有 title, bodyliked_by  三个字段。liked_by 代表喜欢该文章的用户对象id列表。

我们的序列化器ArticleSerializer类如下所示:

from rest_framework import serializers
from .models import Article


class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

如果我们使用上面序列化器去序列化单篇文章资源,我们将得到如下输出数据:

{
   "id": 1,
   "title": "DRF advanced tutorials",
   "body": "This is a good example.",
   "liked_by": [
      2,
      3,
      4
   ]
}

to_representation方法

现在如果我们希望给上面输出数据添加一个total_likes点赞总数的字段,我们只需要在序列化器类里重写to_representation方法。

from rest_framework import serializers
from .models import Article


class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'


    def to_representation(self, value):
        # 调用父类获取当前序列化数据,value代表每个对象实例obj
        data = super().to_representation(value)
        # 对序列化数据做修改,添加新的数据
        data['total_likes'] = value.liked_by.count()
        return data

现在使用新的序列化器类去序列化单篇文章资源,我们将得到如下输出结果。to_representation() 方法改变了我们序列化的输出,并传递了额外的数据。

{ 
   "id": 1,
   "title": "DRF advanced tutorials",
   "body": "This is a good example.",
   "liked_by": [
      2,
      3,
      4
   ],
   "total_likes": 3
}

to_internal_value方法

to_internal_value主要在反序列化时用到,其作用处理API请求携带的数据,对其进行验证并转化为Python的数据类型。

假如我们的API客户端通过请求提交了额外的数据,比如extra_info字段,如下所示。

  {
   "extra_info": {
       "msg": "Hello world!",
   },
   "article_data": {
       "id": 1,
       "title": "DRF advanced tutorials",
       "body": "This is a good example.",
       "liked_by": [
          2,
          3,
          4
       ],
       "total_likes": 3
   }
}

由于extra_info字段不属于我们ArticleSerializer类里的字段,如果我们直接使用ArticleSerializer类对上述数据进行反序列化会出现错误。

事实上反序列化时我们只需要提取article_data然后对其反序列化即可,所以我们可以重写to_internal_value提取我们所需要的数据,忽略不想要的数据。

from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'


    def to_internal_value(self, data):
        # 进提取所需要的数据,对其进行反序列化,data代表未验证的数据
        article_data = data['article_data']
        return super().to_internal_value(article_data)

自定义序列化器类字段

to_representation()to_internal_value()方法的令一个重要用途就是用来自定义序列化类字段。下例为DRF提供的一个官方演示,展示了如何使用这两个方法自定义了一个包含有x, y坐标的字段CoordinateField字段。

# 自定义字段
class CoordinateField(serializers.Field):


    def to_representation(self, value):
        ret = {
            "x": value.x_coordinate,
            "y": value.y_coordinate
        }
        return ret


    def to_internal_value(self, data):
        ret = {
            "x_coordinate": data["x"],
            "y_coordinate": data["y"],
        }
        return ret


# 定义好后,可以在序列化类中使用。
class DataPointSerializer(serializers.ModelSerializer):
    coordinates = CoordinateField(source='*')


    class Meta:
        model = DataPoint
        fields = ['label', 'coordinates']

小结

重写 to_representation()to_internal_value()方法不仅可以改变序列化数据的输出,处理反序列化的输入数据,还可以用来自定义字段。你都明白了吗?

相关阅读

Django REST Framework教程(4): 玩转序列化器(Serializer)

Django REST Framework教程(1): 为什么要学习DRF, 什么是序列化和RESTful的API

Django Rest Framework 序列化关系模型举例 - 好文推荐

  • 15
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值