为什么要用序列化

当我们做前后端分离的项目时,前后端交互一般都是JSON格式的数据,那么我们给前端的数据就要转为JSON格式,就需要我们拿到数据库后的数据进行序列化。在看DRF的序列化之前,先来看看django的序列化

from django.db import models

# Create your models here.

__all__ = ["Book", "Publisher", "Author"]

class Book(models.Model):
title = models.CharField(max_length=32)
CHOICES = ((1, "python"), (2, "Liunux"), (3, "Go"))
category = models.IntegerField(choices=CHOICES)
pub_time = models.DateField()
publisher = models.ForeignKey(to="Publisher")
authors = models.ManyToManyField(to="Author") class Publisher(models.Model):
title = models.CharField(max_length=32) def __str__(self):
return self.title class Author(models.Model):
name = models.CharField(max_length=32) def __str__(self):
return self.name

model.py

from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from djangoDemo.models import Book, Publisher # 第一版用values方法取数据
class BookView(View):
def get(self, request):
book_queryset = Book.objects.values("id", "title", "pub_time", "publisher")
book_list = list(book_queryset)
ret = []
for book in book_list:
book["publisher"] = {
"id": book["publisher"],
"title": Publisher.objects.filter(id=book["publisher"]).first().title,
}
ret.append(book)
# ret = json.dumps(book_list, ensure_ascii=False)
# return HttpResponse(ret)
return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})

序列化

DRF的序列化

从上面的例子中可以看出来,这样我们序列化出来的数据,写法很麻烦。所以我们用DRF的序列化,要用别人的序列化就要遵守别人的规则,首先需要在app里注册

INSTALLED_APPS = [
'django.contrib.admin', ... 'rest_framework',
]

注册好了之后要声明序列化类,在当前app下创建一个py文件

 from rest_framework import serializers

 #  出版社的序列化器,前面的变量要和model里的变量名一样
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32) class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32) class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
pub_time = serializers.DateField()
category = serializers.CharField(source="get_category_display") # 选择的需要指定source publisher = PublisherSerializer() # 一对多的表
authors = AuthorSerializer(many=True) # 多对多的表需要指定many=True

上面我们就写好了序列化的类,注意:匹配上的字段进行序列化,匹配不上则丢弃,所以前端需要哪些字段就写哪些,如果不写的就不序列化

外键关系的序列化是嵌套的序列化器对象 
注意many=True

然后再视图函数里写序列化对象

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book # 导入表
from .serializers import BookSerializer class BookView(APIView):
def get(self, request):
book_queryset = Book.objects.all()
# 拿出来的是一个queryset,用序列化器进行序列化
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data) # 序列化后的数据在data里

注意:当查询出的数据是一个queryset时,需要加many=True,内部会认为是一个可迭代的对象,会去循环。当查询出的是一条数据时,不需要加many=True,会报错

当我们访问这个接口时,返回的数据就是如下的格式

{
"id": 1,
"title": "python从入门到放弃",
"pub_time": "2019-09-10",
"category": "python",
"publisher": {
"id": 1,
"title": "清华"
},
"authors": [
{
"id": 1,
"name": "马云"
},
{
"id": 2,
"name": "刘亦菲"
}
]
}

反序列化

当我们进行post请求的时候,我们需要定义数据格式,然后让前端的妹子传给我们对应的格式。格式确定之后我们还要校验前端妹子传过来的格式和字段,比如字段的类型还有长度,我们不能相信前端妹子的话,妹子说“我没事”。难道就真没事了吗?所以数据校验是必不可少的。

数据格式当然是json格式的,那怎么校验数据呢,在上面我们写了个序列化类,来序列化返回给前端的数据,我们也可以用来校验前端传给我们的数据。因为id是自动递增的,所以前端不需要传,我们也不需要校验,可以加个参数required=False,表示只序列化不反序列化。还有些字段,比如上面的category字段,我们序列化的时候返回的是后面的汉字,而反序列化的时候,我们希望是前面的数字,所以我们需要重写这个字段,如果字段里有read_only=True,表示只序列化。如果是write_only=True,表示只反序列化

返回的数据是上面格式的,我们如果新增数据,希望数据是下面这个格式的

{

        "title": "HTML",
"pub_time": "2019-09-10",
"post_category": 1,
"publisher_id":1,
"author_list": [1,2]
}

注意,前面的key是序列化器里对应的字段

先来改写序列化器

class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False) # 只序列化,不走校验
title = serializers.CharField(max_length=32)
pub_time = serializers.DateField()
category = serializers.CharField(source="get_category_display", read_only=True) # 只序列化用
# 因为前端传的是数字,所以需要重写
post_category = serializers.IntegerField(write_only=True) # 只反序列化用 publisher = PublisherSerializer(read_only=True) # 一对多的表 只序列化用
authors = AuthorSerializer(many=True, read_only=True) # 多对多的表需要指定many=True 只序列化用 publisher_id = serializers.IntegerField(write_only=True) # 只反序列化用
author_list = serializers.ListField(write_only=True) # 只反序列化用 def create(self, validated_data):
# validated_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

在来改写视图函数,新增post请求

class BookView(APIView):
def get(self, request):
book_queryset = Book.objects.all()
# 拿出来的是一个queryset,用序列化器进行序列化
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data) # 序列化后的数据在data里 def post(self, request):
# 确定数据类型以及数据结构
# 对前端传来的数据进行校验
book_obj = request.data # post传来的数据
ser_obj = BookSerializer(data=book_obj) # 有data参数,表示反序列化
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors) # 返回错误

这样,当我们提交像上面一样的数据格式之后,在看get请求,就返回如下的数据

[
{
"id": 1,
"title": "python从入门到放弃",
"pub_time": "2019-09-10",
"category": "python",
"publisher": {
"id": 1,
"title": "清华"
},
"authors": [
{
"id": 1,
"name": "马云"
},
{
"id": 2,
"name": "刘亦菲"
}
]
},
{
"id": 2,
"title": "Linux跑路",
"pub_time": "2019-09-18",
"category": "Liunux",
"publisher": {
"id": 2,
"title": "北大"
},
"authors": [
{
"id": 2,
"name": "刘亦菲"
}
]
},
{
"id": 3,
"title": "HTML",
"pub_time": "2019-09-10",
"category": "python",
"publisher": {
"id": 1,
"title": "清华"
},
"authors": [
{
"id": 1,
"name": "马云"
},
{
"id": 2,
"name": "刘亦菲"
}
]
}
]

序列化返回给前端的数据

put反序列化

上面的序列化是post请求的,那我们修改数据的时候可能是只对某一个字段进行修改

路由:

urlpatterns = [
url(r'^book/$', BookView.as_view()),
url(r'^book/(?P<id>\d+)', BookEditView.as_view()),
]

在 BookSerializer 序列化类里添加一个update方法

def update(self, instance, validated_data):
# instance 更新的book_obj对象
# validated_data 校验通过的数据
instance.title = validated_data.get("title",instance.title)
instance.pub_time = validated_data.get("pub_time",instance.pub_time)
instance.category = validated_data.get("post_category",instance.category)
instance.publisher_id = validated_data.get("publisher_id",instance.publisher_id)
if validated_data.get("author_list"): # 可能有多个值
instance.author.set(validated_data["author_list"])
instance.save() # 保存
return instance

因为不知道修改的是哪个字段,所以都要写

在写put请求

class BookEditView(APIView):
def get(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(book_obj) # 查询出的是一条数据,不需要加 many=True
return Response(ser_obj.data) def put(self, request, id):
book_obj = Book.objects.filter(id=id).first()
# instance必传,data=request.data前端传的参数,partial=True部分修改
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data) # 返回数据,注意不是ser_obj.validated_data
return Response(ser_obj.errors)

最新文章

  1. 使用OPENROWSET、Microsoft.ACE.OLEDB实现大数据量的高效导入
  2. 【UVALive 4642】Malfatti Circles(圆,二分)
  3. 在数据库中如果组合主键(假设为stuID和stuName)存在则更新,不存在则新增
  4. ADB指令
  5. 利用Roslyn把C#代码编译到内存中并进行执行
  6. hdu 1695 GCD 莫比乌斯反演入门
  7. ARM学习日记
  8. json 序列化和反序列化
  9. hdu 3371 Connect the Cities (最小生成树Prim)
  10. JavaScript之面向对象学习八(继承)
  11. C# 方法的可选参数、命名参数
  12. 【可视化】Echarts3图层
  13. JMeter数据库操作详解
  14. 01-vagrant安装centos7
  15. 手写DotNet Core 认证授权代码
  16. javascript中事件对象注册与删除
  17. ⌈洛谷1312⌋⌈NOIP提高组2011⌋Mayan游戏【搜索】
  18. Linux mmc framework1:软件架构
  19. MySQL Memory--内存分配相关参数
  20. PAT 1009 说反话 (20)(代码)

热门文章

  1. 剑指Offer-31.整数中1出现的次数(从1到n整数中1出现的次数)(C++/Java)
  2. HTML引入JS、CSS的各种方法
  3. 前端笔记之React(七)redux-saga&amp;Dva&amp;路由
  4. 史上最全HashMap遍历方式
  5. php-laravel框架用户验证(Auth)模块解析(一)
  6. redis集群之Cluster
  7. CSP-S 爆零记
  8. Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
  9. Git 实用命令记录
  10. wpf/winform获取windows10系统颜色和主题色