在 《DRF 序列化器(Serializer)》一文中已对 DRF 序列化器进行了介绍和演示,本篇文章将在上一篇基础上进一步介绍和演示模型序列化器(ModelSerializer),并附上演示案例。
模型序列化器可以对应 Django 的模型类,DRF 提供了ModelSerializer
模型序列化基类来快速创建一个模型序列化器。
ModelSerializer
比 Serializer
额外提供了:
Serializer
生成 validators
,比如 unique_together
create()
和 update()
的实现TestModelSerializer(instance=None,data=empty,**kwargs)
用于序列化时,将模型类对象传入 instance
参数;
用于反序列化时,将要被反序列化的数据传入 data
参数;
除了 instance
和 data
参数外,在构造 Serializer
对象时,还可以通过 context
参数额外添加数据,通过 context
添加的数据,可以通过 Serializer
对象的 context
属性获取;
某个字段不属于指定的 model
,它是 write_only
,需要用户传进来,但我们不能对它进行 save( )
,因为 ModelSerializer
是基于 Model
,这个字段在 Model
中没有对应,这个时候,我们需要重载 validate
进行验证后再数据清洗。
from rest_framework import serializers
class TestModelSerializer(serializers.ModelSerializer)
class Meta:
model = Test
def validate(self, attrs):
del attrs["code"]
return attrs
某个字段不属于指定的 model
,它是 read_only
,只需要将它序列化传递给用户,但是在这个 model
中,没有这个字段时,需要用到 SerializerMethodField
。比如,在数据库中储存了用户加入的日期,但是现在需要计算用户加入多久,就需要使用自定义的字段。
class TeacherModelSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField()
# 方法写法:get_ + 字段
def get_days_since_joined(self, obj):
# obj指这个model的对象
return (now() - obj.date_joined).days
class Meta:
model = Teacher
# model.py
class Teacher(models.Model):
name = models.CharField(
null=False,
max_length=255,
verbose_name='姓名'
)
age = models.IntegerField(
null=False,
verbose_name='年龄'
)
sex = models.IntegerField(
null=False,
verbose_name='性别'
)
active = models.BooleanField(
# 默认值为 True
default=True,
verbose_name='是否活跃'
)
description = models.CharField(
max_length=255,
null=True,
blank=True,
verbose_name='描述'
)
date_joined = models.DateTimeField(
default=timezone.now,
verbose_name='加入时间'
)
from django.urls import path
from .views import TeacherView
urlpatterns = [
path('teacher/' , TeacherView.as_view()),
]
# views.py
class TeacherView(APIView):
def get(self, request, pk):
"""
序列化器,序列化阶段的调用
"""
if pk == 'all':
# 1、获取数据集
teacher_list = Teacher.objects.all()
# 2、实例化序列化器,得到序列化对象
serializer = TeacherModelSerializer(instance=teacher_list, many=True)
# 3、调用序列化对象的data属性方法获取转换后的数据
data = serializer.data
# 4、响应数据
return JsonResponse({'data': data, 'message': 'success'})
else:
query = Teacher.objects.filter(id=pk)
if query.count():
teacher = query.first()
serializer = TeacherModelSerializer(instance=teacher)
data = serializer.data
return JsonResponse({'data': data, 'message': 'success'})
else:
return JsonResponse({'message': 'ID不存在'})
def post(self, request, pk):
"""反序列化,采用字段选项来验证数据"""
# 1、接收客户端提交的数据
# 1.1 实例化序列化器,获取序列化对象
data = request.data
# 1.2 调用序列化对象验证数据
serializer = TeacherModelSerializer(data=data)
# 1.3 获取验证结果
serializer.is_valid() # 不抛出异常
serializer.is_valid(raise_exception=True) # 抛出异常
# 2、操作数据
serializer.save()
# 3、返回数据
return JsonResponse({'data': data, 'message': '添加成功'})
def put(self, request, pk):
"""反序列化,采用字段选项来验证数据"""
# 1、根据客户端提交的数据获取指定数据
# 1.1 实例化序列化器,获取序列化对象
pk = request.data.get('id', '')
teacher = Teacher.objects.filter(id=pk).first()
data = request.data
# 1.2 调用序列化对象验证数据
serializer = TeacherModelSerializer(instance=teacher, data=data)
# 1.3 获取验证结果
serializer.is_valid(raise_exception=True) # 抛出异常
# 2、操作数据
# 会根据实例化序列化器的时候是否传入instance属性来自动调用create或者update方法,如果传入instance属性,调用update方法,没有传入instance属性,调用create方法
serializer.save()
# 3、返回数据
return JsonResponse({'data': data, 'message': '修改成功'})
# serializers.py
class TeacherModelSerializer(serializers.ModelSerializer):
class Meta:
# 1、指定对应的 Django 模型,必填
model = Teacher
# 2、声明转换字段必填,如果需要全部转换可以设置为 __all__
# fields = '__all__'
fields = ["id", "name", "age", "sex", "classmate", "nickname"]
# read_only_fields指明只读字段,即仅用于序列化输出的字段
read_only_fields = ['id', 'date_joined']
# 也可以使用exclude可以明确排除掉哪些字段
# exclude = ['id']
# 字段额外选项信息,如错误的提示信息,选填
extra_kwargs = {
"name": {
'required': True
},
"age": {
"max_value": 20,
"min_value": 5,
"error_messages": {
"max_value": "must younger than 20",
"min_value": "must older than 5",
}
}
}
# 全局钩子
def validate(self, attrs):
"""
验证来自客户端的所有字段
"""
if not attrs['active'] and attrs['description']:
raise serializers.ValidationError(
detail='非active老师需要添加描述',
code='validate'
)
return attrs