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
标签:value,internal,representation,序列化,data,class From: https://www.cnblogs.com/dreammooncy/p/18175476