DRF两大利器为Serizlizer序列化器和视图,而序列化器又分为序列化和反序列化,本篇文章首先来看下DRF序列化器的常用序列化方法。
首先来看使用Django开发REST接口时的表现,示例代码如下:
# views.py
from datetime import datetime
class BooksAPIVIew(View):
"""
查询所有图书、增加图书
"""
def get(self, request):
"""
查询所有图书
路由:GET /books/
"""
queryset = BookInfo.objects.all()
book_list = []
# 将BookInfo对象转换为字典
for book in queryset:
book_list.append({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image.url if book.image else ''
})
# book_list为包含很多字典的列表
return JsonResponse(book_list, safe=False)
def post(self, request):
"""
新增图书
路由:POST /books/
"""
json_bytes = request.body
json_str = json_bytes.decode()
book_dict = json.loads(json_str)
# 此处详细的校验参数省略
book = BookInfo.objects.create(
btitle=book_dict.get('btitle'),
bpub_date=datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date()
)
return JsonResponse({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image.url if book.image else ''
}, status=201)
当我们得到Queryset时或者得到一个BookInfo对象时,需要将BookInfo对象转换为字典,将包含字典类型数据的列表转换为json数据响应回去。其中将BookInfo对象转换为字典的代码冗余的厉害,此时serializer就可以大显身手了。
使用序列化器首先需要在serializers.py中定义序列化器类:
字段名称和模型类中的字段名相同,字段的选项约束有很多,默认约束required为True!
详细可以参看官方文档:https://www.django-rest-framework.org/
Github源码:https://github.com/encode/django-rest-framework/tree/master
# 需要继承DRF的serilalizers中的Serializer
from rest_framework import serializers
from .models import BookInfo
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
btitle = serializers.CharField(
min_length=3,
max_length=10,
error_messages={
'min_length': '书名要大于3个字符',
'max_length': '书名要小于10个字符'
}
)
bpub_date = serializers.DateField()
bread = serializers.IntegerField()
bcomment = serializers.IntegerField(label='评论量', required=False)
创建Serializer对象
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取
掌握了上述知识后我们就可以开始进行序列化操作了
class Book2View(View):
def get(self, request):
# 序列化列表
blist = BookInfo.objects.all()
# 1.创建序列化对象,如果被序列化的是包含多条数据的查询集QuerySet
# 需要添加many=True参数补充说明
# 以列表为参数,列表中是模型类对象
serializer = serializers.BookSerializer(blist, many=True)
# 2.调用属性data,通过data属性可以获取序列化后的数据
# 获取转换后的列表,列表中是有序字典对象
"""
[OrderedDict([('id', 2), ('btitle', '天龙八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40)]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80)])]
"""
book_dict_list = serializer.data
# 响应
return JsonResponse(book_dict_list, safe=False)
关联对象嵌套序列化
如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。注:书籍与英雄的关系为一对多
在定义序列化器类的代码中添加如下代码,注意在定义关联属性时,必须添加约束read_only = True
# 关系属性输出的3种方案
# 1.主键 此字段将被序列化为关联对象的主键。
# heros = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
# 2.字符串
# heros = serializers.StringRelatedField(read_only=True, many=True)
# 3.自定义序列化器
heros = HeroSerializer(read_only=True, many=True)
如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,则在约束中添加many=True参数即可。
PrimaryKeyRelatedField: 此字段将被序列化为关联对象的主键
StringRelatedField:此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)(定义模型类时添加__str__方法)
HeroSerializer:使用关联对象的序列化器,需要自己定义关联对象的序列化器
序列化器的序列化方法帮助我们封装了将python类型(模型类对象、模型类对象的列表)转换为字典的过程,加快开发效率。
# 将模型类对象转换成字典的过程
serializer = serializers.HeroSerializer(hero)
hero_dict = serializer.data
# 将模型类对象的列表转换为字典列表
serializer = serializers.BookSerializer(blist, many=True)
book_dict_list = serializer.data