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

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

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

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, body和 liked_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()方法不仅可以改变序列化数据的输出,处理反序列化的输入数据,还可以用来自定义字段。你都明白了吗?

原文链接:https://blog.csdn.net/weixin_42134789/article/details/115191672

posted @ 2024-05-06 17:21  沉岩  阅读(4)  评论(0编辑  收藏  举报