一、Django的序列化方法
1、为什么要用序列化组件
做前后端分离的项目,我们前后端数据交互一般都选择JSON,JSON是一个轻量级的数据交互格式。
那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到的数据进行序列化。
2、表的构建
CHOICES = ((1, "python"), (2, "linux"), (3, "go")) # 书籍表 class Book(models.Model): title = models.CharField(max_length=64) category = models.IntegerField(choices=CHOICES) # 书籍分类 pub_time = models.DateField() publisher = models.ForeignKey(to="Publisher") authors = models.ManyToManyField(to="Author") class Meta: verbose_name = '书籍' verbose_name_plural = verbose_name def __str__(self): return self.title # 出版社表 class Publisher(models.Model): title = models.CharField(max_length=64) class Meta: verbose_name = '出版社' verbose_name_plural = verbose_name def __str__(self): return self.title # 作者表 class Author(models.Model): name = models.CharField(max_length=32) class Meta: verbose_name = '作者' verbose_name_plural = verbose_name def __str__(self): return self.name
3、希望构建的字典格式
book_list = [ { "id": 1, "title": "", "publisher": { # 外键 "id": 1 "title": "" }, "authors": [{}, {}] # 多对多 }, { "id": 2, "title": "", "publisher": { # 外键 "id": 1 "title": "" }, "authors": [{}, {}] # 多对多 }, ]
4、方法一
在Django中使用Json模块序列化 class BooksView(views.View): def get(self, request): book_queryset = Book.objects.values("id", "title", "pub_time", "publisher") book_list = list(book_queryset) # 把queryset类型转换成列表 # 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的 ret = [] for book in book_list: publisher_obj = Publisher.objects.filter(id=book["publisher"]).first() # 修改原字典中的publisher对应的值 book["publisher"] = { "id": publisher_obj.id, "title": publisher_obj.title } # 把新的字典追加到一个空列表中 ret.append(book) ret = json.dumps(ret, ensure_ascii=False, cls=MyJson) return HttpResponse(ret)
5、方法二
使用JsonResponse,自动帮我们重写了JSONEncoder里面的default方法,解决时间字段的问题 class BooksView(views.View): def get(self, request): book_queryset = Book.objects.values("id", "title", "pub_time", "publisher") book_list = list(book_queryset) # 把queryset类型转换成列表 # 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的 ret = [] for book in book_list: publisher_obj = Publisher.objects.filter(id=book["publisher"]).first() # 修改原字典中的publisher对应的值 book["publisher"] = { "id": publisher_obj.id, "title": publisher_obj.title } # 把新的字典追加到一个空列表中 ret.append(book) return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False})
6、方法三
使用Django自带的序列化模块 from django.core import serializers # 能够得到我们要的效果 结构有点复杂 class BooksView(views.View): def get(self, request): book_queryset = Book.objects.all() ret = serializers.serialize("json", book_queryset, ensure_ascii=False) return HttpResponse(ret)
二、DRF序列化的介绍
1、介绍
下载DRF模块:pip install djangorestframework 导入: from rest_framework.views import APIView from rest_framework.response import Response 首先,我们要用DRF的序列化,就要遵循DRF框架的一些标准, -- Django我们CBV继承类是View,现在DRF我们要用APIView -- Django中返回的时候我们用HTTPResponse,JsonResponse,render ,DRF我们用Response
2、APIView跟View区别
-- APIView继承了View -- APIView的as_view方法实现了csrf中间件的豁免(用DRF不需要再把settings的csrf中间件注释掉了) -- 重新封装了request request._request可以拿到旧的request request.query_params 旧的request.GET request.data 除了GET请求外的所有的数据(已经序列化好的数据) validated_data是通过校验的数据,也会封装到data里面 -- DRF有自己的序列化模块 from rest_framework import serializers
三、DRF序列化步骤
1、声明序列化器
# serializers.py文件 from rest_framework import serializers from libsys.models import Book CHOICES = ((1, "python"), (2, "linux"), (3, "go")) # 继承serializers.Serializer class PublisherSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=64) class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField(max_length=32) # 字段的声明和models相类似 class BookSerializer(serializers.Serializer): # POST校验的时候required=False声明不需要校验这个字段 id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=64) pub_time = serializers.DateField() # 选择字段,显示的是数字 # category = serializers.ChoiceField(choices=CHOICES) # 把选择字段显示成字符类型,source参数后面跟的是ORM操作 # read_only=True表示这个字段只在渲染前端的时候使用 category = serializers.CharField(source='get_category_display', read_only=True) # write_only=True表示这个字段只在POST提交数据,做校验的时候使用 post_category = serializers.IntegerField(write_only=True) # 外键需要设置额外的序列化器对它进行序列化 publisher = PublisherSerializer(read_only=True) publisher_id = serializers.IntegerField(write_only=True) # 多对多字段需要设置额外的序列化器对它进行序列化,且声明many=True authors = AuthorSerializer(many=True, read_only=True) author_list = serializers.ListField(write_only=True) def create(self, validated_data): # validated_data是通过校验的数据,最后也会封装到data里面 #通过ORM操作给Book表增加数据 book_obj = Book.objects.create(title=validated_data["title"], pub_time=validated_data["pub_time"], category=validated_data["post_category"], publisher_id=validated_data["publisher_id"]) book_obj.authors.add(*validated_data["author_list"]) return book_obj
2、在视图函数中调用
from libsys.models import Book, Publisher, Author from rest_framework.views import APIView from rest_framework.response import Response from .serializers import BookSerializer # Create your views here. # 书籍列表 class BookView(APIView): def get(self, request): book_queryset = Book.objects.all() # 声明一个序列化器 # 用序列化器去序列化queryset(queryset有多个对象的时候,需要声明many=True) # 把数据提交到序列化器,跟序列化器的字段进行匹配,匹配成功就进行序列化 ser_obj = BookSerializer(book_queryset, many=True) return Response(ser_obj.data) # 新增书籍 def post(self, request): # 前端传过来的数据应该也是这样的 # {"id""title", # category: 1 # publisher: 1 # authors: [1, 2] # } # 获取前端传过来的数据 book_obj = request.data # 用序列化器做校验 ser_obj = BookSerializer(data=book_obj) if ser_obj.is_valid(): # 校验通过,新增书籍 ser_obj.save() # 这里的save方法会去调用序列化器的create方法 print(ser_obj.validated_data) # validated_data是通过校验的数据,也会封装到data里面 return Response(ser_obj.data) # 校验不通过返回错误信息 return Response(ser_obj.errors)
3、注意事项
1. 外键和多对多字段的序列化需要额外再设置序列化器 2. 序列化 序列化器的参数是queryset和many 3. 反序列化 序列化器的参数是data=提交上来的数据 4. 序列化器字段类型不统一的情况 反序列化要用的一些字段通过一些参数跟序列化区分开 -- required=False -- read_only=True -- write_only=True 5. 反序列化的验证 is_valid() --> 校验数据 save() --> 调用序列化器的create方法
4、DRF的钩子方法
5、小结
-- 序列化 -- 声明一个序列化器 class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) pub_time = serializers.DateField() -- 视图里序列化我们的queryset ser_obj = BookSerializer(queryset, many=True) return Response(ser_obj.data) -- 实现流程 -- 如果指定了many=True -- 把queryset当成可迭代对象去循环 得到每个模型对象 -- 把每个模型对象放入序列号器进行序列化 -- 进行字段匹配 匹配上的字段进行序列化 匹配不上丢弃 -- 必须满足序列化的所有字段要求 -- 反序列化 -- 获取前端传过来的数据 -- 用序列化器进行校验 ser_obj = BookSerializer(data=request.data) if ser_obj.is_valid(): ser_obj.save()# 调用create方法 return Response(ser_obj.data) else: return Response(ser_obj.errors) -- 写create方法 在create方法里用ORM操作创建新对象