作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能
-
定义序列化器
- Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers
python manage.py startapp sers
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32,verbose_name="书籍名称") price = models.IntegerField(verbose_name="价格") pub_date = models.DateField(verbose_name="出版日期")
我们想为Book模型类提供一个序列化器,可以定义如下:
from rest_framework import serializers class BookSerializer(serializers.Serializer): title = serializers.CharField() price = serializers.IntegerField() pub_date = serializers.DateField()
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
- Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
-
创建Serializer对象
-
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:Serializer(instance=None, data=empty, **kwarg)
-
说明:
-
用于序列化时,将模型类对象传入instance参数
-
用于反序列化时,将要被反序列化的数据传入data参数
-
除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如 serializer = AccountSerializer(account, context={'request': request})
-
-
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
-
使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
-
序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
-
序列化器的字段声明类似于我们前面使用过的表单系统。
-
开发restful api时,序列化器会帮我们把模型数据转换成字典.
-
drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
-
-
-
序列化器的使用
-
序列化器的使用分两个阶段:
-
处理客户端请求时,使用序列化器可以完成对数据的反序列化。
-
处理服务器响应时,使用序列化器可以完成对数据的序列化。
-
-
序列化
-
基本序列化
- 先查询出一个学生对象
from sers.models import Book book = Book.objects.get(pk=1)
- 构造序列化器对象
from .serializers import BookSerializer bookSer = BookSerializer(instance=book)
- 获取序列化数据,通过data属性可以获取序列化后的数据
- 路由
# urls.py path("sers/", include("sers.urls")), # sers.urls path('books/(\d+)', BookView.as_view()),
- 视图
from rest_framework.response import Response from rest_framework.views import APIView from .models import Book from .sers import BookSerializer class BookView(APIView): def get(self, request,id): book = Book.objects.get(pk=id) bs = BookSerializer(instance=book) return Response(bs.data)
- 如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
class BookView(APIView): def get(self, request): # book = Book.objects.get(pk=1) books = Book.objects.all() bs = BookSerializer(instance=books, many=True) return Response(bs.data)
- 先查询出一个学生对象
-
-
-
反序列化
-
数据验证
-
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证。
from sers.sers import BookSerializer bs = BookSerializer(data={"title":"小王子","price":100}) bs.is_valid() # 必须先要is_valid,才会有bs.validated_data和bs.errors False bs.validated_data {} bs.errors {'pub_date': [ErrorDetail(string='This field is required.', code='required')]}
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
-
validate_字段名,对
<field_name>
字段进行验证,如class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.IntegerField(required=True) pub_date = serializers.DateField(required=True) def validate_title(self, value): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") return value
-
测试
from sers.sers import BookSerializer bs = BookSerializer(data={"title":"小王子","price":100}) bs.is_valid() False bs.errors {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')], 'pub_date': [ErrorDetail(string='This field is required.', code='required')]}
-
validate,在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.IntegerField(required=False) pub_date = serializers.DateField(required=False) bread = serializers.IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False) bcomment = serializers.IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False) def validate_title(self, value): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") return value def validate(self, data): bread = data.get("bread") bcomment = data.get("bcomment") if bread < bcomment: raise serializers.ValidationError('阅读量小于评论量') return data
-
反序列化-保存数据,
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过实现create()和update()两个方法来实现。
在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了,book = serializer.save()
-
-
基于APIView的接口实现
- 路由
urlpatterns = [ path('book/', views.BookView.as_view()), re_path('book/(\d+)', views.BookDetailView.as_view()), ]
- 视图
# Create your views here. from rest_framework.views import APIView # 设计增删改查查接口 # 视图 class BookView(APIView): def get(self, request): books = Book.objects.all() bs = BookSerializer(instance=books, many=True) return Response(bs.data) def post(self, request): bs = BookSerializer(data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) class BookDetailView(APIView): def get(self, request, pk): book = Book.objects.get(pk=pk) bs = BookSerializer(instance=book) return Response(bs.data) def put(self, request, pk): instance = Book.objects.get(pk=pk) bs = BookSerializer(instance=instance, data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) def delete(self, request, pk): Book.objects.get(pk=pk).delete() return Response()
- serializer
# 序列化器 from rest_framework import serializers from rest_framework.response import Response from .models import Book class BookSerializer(serializers.Serializer): title = serializers.CharField() price = serializers.IntegerField() pub_date = serializers.DateField() def create(self, validated_data): new_book = Book.objects.create(**validated_data) return new_book def update(self, instance, validated_data): Book.objects.filter(pk=instance.pk).update(**validated_data) instance = Book.objects.get(pk=instance.pk) return instance
- 路由
-