前言:
源码讲解:
class BaseSerializer(Field):
"""
The BaseSerializer class provides a minimal class which may be used
for writing custom serializer implementations.
Note that we strongly restrict the ordering of operations/properties
that may be used on the serializer in order to enforce correct usage.
In particular, if a `data=` argument is passed then:
.is_valid() - Available.
.initial_data - Available.
.validated_data - Only available after calling `is_valid()`
.errors - Only available after calling `is_valid()`
.data - Only available after calling `is_valid()`
If a `data=` argument is not passed then:
.is_valid() - Not available.
.initial_data - Not available.
.validated_data - Not available.
.errors - Not available.
.data - Available.
"""
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
参数:
- instance: 实例, 可以接收Model实例, 或者 查询集QuerySet
- data: 接收的数据, (反序列化所需要的数据)
序列化
如果只是序列化一个对象时, 只需要将对象,传给参数instance
如果需要序列化多个对象,或者查询集时,需要传入instance
和many=True
两个参数
反序列化
如果是,创建一个对象时,只需要传入data
如果是,更新操作,则需要传入data
和instance
序列化器
REST framework的核心就是 序列化器。
它提供了一个serializer
类,它可以非常方便的序列化模型实例和查询集为JSON或者其他内容的形式。
它还提供反序列化功能,允许在验证传入的数据后将其转换为复杂类型
一、定义序列化器
接django框架部分的crm案例,在crm应用目录下创建serializers.py文件,编写代码如下:
from rest_framework import serializers
from crm.models import Student
class StudentSerializer(serializers.Serializer):
"""
学生序列化器
"""
id = serializers.IntegerField(label='学生id', read_only=True)
name = serializers.CharField(label='姓名')
sex = serializers.IntegerField(label='性别', default=1)
age = serializers.IntegerField(label='年龄', required=False, allow_null=True)
qq = serializers.CharField(label='qq号码', required=False, allow_null=True)
phone = serializers.CharField(label='手机号码', required=False, allow_null=True)
channel = serializers.CharField(label='渠道', read_only=True)
c_time = serializers.DateTimeField(label='创建时间', read_only=True)
def create(self, validated_data):
"""
创建对象
:param validated_data:
:return:
"""
return Student.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
更新对象
:param instance:
:param validated_data:
:return:
"""
for key, value in validated_data.items():
setattr(instance, key, value)
instance.save()
return instance
序列化器类的第一部分定义了要序列化/反序列化的字段。create()
和update()
方法定义了在调用serializer.save()
时如何创建或修改实例
二、使用序列化器
2.1 序列化
进入Django Shell
python manage.py shell
先导入一些需要用到的对象
from crm.models import Student
from crm.serializers import StudentSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
obj = Student.objects.first()
序列化这个实例
s = StudentSerializer(obj)
s.data
# {'id': 3, 'name': '赵六', 'sex': 1, 'age': 22, 'qq': '1111', 'phone': '18684720553', 'channel': '抖音', 'c_time': '2022-01-14T21:45:06.037745+08:00'}
我们已经将模型实例转换为Python原生数据类型。为了完成序列化过程,我们将数据呈现为json。
JSONRenderer().render(s.data)
# b'{"id":3,"name":"\xe8\xb5\xb5\xe5\x85\xad","sex":1,"age":22,"qq":"1111","phone":"18684720553","channel":"\xe6\x8a\x96\xe9\x9f\xb3","c_time":"2022-01-14T21:45:06.037745+08:00"}'
我们还可以序列化查询集而不只是模型实例,序列化时,再传入参数many=True.
ss = StudentSerializer(Student.objects.all(), many=True)
ss.data
# [OrderedDict([('id', 3), ('name', '赵六'), ('sex', 1), ('age', 22), ('qq', '1111'), ('phone', '18684720553'), ('channel', '抖音'), ('c_time', '2022-01-14T21:45:06.037745+08:00')]), OrderedDict([('id', 15), ('name', '心蓝'), ('sex', 1), ('age', 20), ('qq', '111'), ('phone', '1111123'), ('channel', '百度'), ('c_time', '2022-02-08T21:59:54.743096+08:00')]), OrderedDict([('id', 21), ('name', '西瓜'), ('sex', 1), ('age', 20), ('qq', '123456789'), ('phone', '987654321'), ('channel', '抖音'), ('c_time', '2022-02-09T21:15:37.199509+08:00')])]
2.2 反序列化
反序列化是相似的,首先将序列化数据(json)解析为原生python数据类型(省略),然后将其填充到一个序列器对象中。
data = {
"name": "心蓝",
"sex": 1,
"age": 18,
"qq": "123123",
"phone": "13888888888"
}
s = StudentSerializer(data=data)
s.is_valid() # 校验
# True
s.validated_data # 校验后的数据
# OrderedDict([('name', '心蓝'), ('sex', 1), ('age', 18), ('qq', '123123'), ('phone', '13888888888')])
s.save() # 创建对象
# <Student: 心蓝>
三、使用模型序列化器
上面的StudentSerializer
类 复制了大量Student
模型中的的信息。RESTframework
提供了一个ModelSerializer
,它可以根据模型自动创建Serializer
类,代码更简洁。
再次打开crm/serializers.py模块,并用以下代码替换StudentSerializer类。
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ['id', 'name', 'sex', 'age', 'phone', 'qq', 'c_time']
序列化器的一个很好的属性是,可以通过打印序列化器实例的表示形式来检查它的所有字段。
进入Django shell
然后尝试如下操作:
In [1]: from crm.serializers import StudentSerializer
In [2]: s = StudentSerializer()
In [3]: print(s)
StudentSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(help_text='姓名', label='姓名', max_length=20)
age = IntegerField(allow_null=True, help_text='年龄', label='年龄', max_value=32767, min_value=-32768, required=False)
sex = IntegerField(help_text='性别', label='性别', max_value=32767, min_value=-32768, required=False)
qq = CharField(allow_blank=True, allow_null=True, help_text='qq号码', label='Qq号码', max_length=20, required=False, validators=[<UniqueValidator(queryset=Student.objects.all())>])
phone = CharField(allow_blank=True, allow_null=True, help_text='手机号码', label='手机号码', max_length=20, required=False, validators=[<UniqueValidator(queryset=Student.objects.all())>])
c_time = DateTimeField(label='创建时间', read_only=True)
channel = PrimaryKeyRelatedField(allow_null=True, help_text='渠道来源', label='渠道', queryset=Channel.objects.all(), required=False)
ModelSerializer类并没有做什么特别神奇的事情,它们只是创建序列化器类的一个快捷方式:
- 一组自动确定的字段。
create()
和update()
方法的简单默认实现。
四、使用序列化器编写普通的Django视图
接下来我们使用新的序列化器来编写一些API视图。当前不使用任何REST framework
的其他特性,只写普通的django视图。
编辑crm/views.py
添加如下内容:
def student_list(request):
"""
学生列表,创建学生视图
:param request:
:return:
"""
if request.method == 'GET':
objs = Student.objects.all()
# 序列化
serializer = StudentSerializer(objs, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
# 序列化
serializer = StudentSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
else:
return JsonResponse(serializer.errors, status=400)
def student_detail(request, pk):
"""
检索,更新或者删除一个学生
:param request:
:param pk:
:return:
"""
try:
obj = Student.objects.get(pk=pk)
except Student.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
# 序列化
serializer = StudentSerializer(obj)
return JsonResponse(serializer.data)
elif request.method == 'PUT':
# 反序列化
data = JSONParser().parse(request)
serializer = StudentSerializer(obj, data=data)
# 校验
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
obj.delete()
return HttpResponse(status=204)
路由配置如下:
urlpatterns = [
path('projects/', views.student_list),
path('projects/<int:pk>/', views.student_detail)
]
那么通过/students/和/students/id/就可以访问对应的接口了。