作用:
-
序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
-
反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
-
反序列化,完成数据校验功能
定义序列化器
-
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。 接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers
python manage.py startapp sers
pythonfrom 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模型类提供一个序列化器,可以定义如下:
pythonfrom rest_framework import serializers class BookSerializer(serializers.Serializer): title = serializers.CharField() price = serializers.IntegerField() pub_date = serializers.DateField()
**注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。**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,或者把客户端发送过来的数据转换字典.
-
序列化器的使用
-
序列化器的使用分两个阶段:
-
处理客户端请求时,使用序列化器可以完成对数据的反序列化。
-
处理服务器响应时,使用序列化器可以完成对数据的序列化。
-
#### 序列化
*
##### 基本序列化
* 先查询出一个学生对象
```python
from sers.models import Book
book = Book.objects.get(pk=1)
```
* 构造序列化器对象
```python
from .serializers import BookSerializer
bookSer = BookSerializer(instance=book)
```
* 获取序列化数据,通过data属性可以获取序列化后的数据
* 路由
```python
# urls.py
path("sers/", include("sers.urls")),
# sers.urls
path('books/(\d+)', BookView.as_view()),
```
* 视图
```python
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** 参数补充说明
```python
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构造参数,进而进行验证。
```python
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>`字段进行验证,如
```python
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
```
* 测试
```python
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方法来验证,如
```python
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的接口实现
* 路由
```python
urlpatterns = [
path('book/', views.BookView.as_view()),
re_path('book/(\d+)', views.BookDetailView.as_view()),
]
```
* 视图
```python
# 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
```python
# 序列化器
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
```