drf篇:序列化类Serializer

序列化类Serializer

  • 简介
  • 序列化类基本使用
  • 序列化类常用字段和字段参数
  • 序列化类Serializer的反序列化
  • 局部和全局钩子
  • 序列化类ModelSerializer的使用
  • 多表序列化
  • 请求与响应

1、serializers简介

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
# 序列化组件--->一个类,可以完成下面的事 1. 序列化,把模型对象(book,queryset)转换成字典,经过drf的response以后变成json字符串 2. 反序列化,把客户端发送过来的数据(前端json格式字符串),经过request.data以后变成字典,序列化器可以把字典转成模型,存到数据库 3. 反序列化,完成数据校验功能---》前端传入的数据,长短,是否是邮箱,手机号。。可以做校验 # 1 序列化的功能 表中数据,序列化后,以json格式返回给前端

2、序列化类基本使用

2.1路由

复制代码
  • 1
path('books/', views.BookAPIView.as_view()),

2.2 视图类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
from .models import Book from .serializer import BookSerializer class BookAPIView(APIView): def get(self,request): # 取出所有图书的qs对象 books=Book.objects.all() # 借助于序列化类--》写一个序列化类 # 类实例化时:instance:要序列化的对象 many:True 多条 先记着这两个参数 ser=BookSerializer(instance=books,many=True) # ser.data 完成了序列化 print(ser.data) # 把qs对象,转成了字典,根据序列化类中你写的字段转的 return Response(ser.data)

2.3 序列化类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
from rest_framework import serializers class BookSerializer(serializers.Serializer): # 一定要继承Serializer # 写要序列化的字段,比如,不想把作者给前端 name = serializers.CharField() # 字段类,跟models中一一对应 price = serializers.IntegerField() # 字段类,跟models中一一对应 publish = serializers.CharField() # 字段类,跟models中一一对应 author = serializers.CharField() # 字段类,跟models中一一对应

3、序列化类常用字段和字段参数

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
# 字段类和字段属性 ### 字段类:跟models一一对应,但是比它多 # BooleanField # NullBooleanField # CharField # EmailField # RegexField # SlugField # URLField # UUIDField # IPAddressField # IntegerField # FloatField # DecimalField # DateTimeField # DateField # TimeField # ChoiceField # FileField # ImageField ------ 以上都是models有的----下面是serializer独有的--- # ListField # DictField #### 字段属性--->写在字段类中的---》干啥用?反序列化校验用的!!!! ## 选项参数 # CharField max_length 最大长度 min_lenght 最小长度 allow_blank 是否允许为空 trim_whitespace 是否截断空白字符 # IntegerField max_value 最小值 min_value 最大值 # 通用参数: ### 重点讲 read_only 表明该字段仅用于序列化输出,默认False write_only 表明该字段仅用于反序列化输入,默认False required 表明该字段在反序列化时必须输入,默认True default 反序列化时使用的默认值 allow_null 表明该字段是否允许传入None,默认False error_messages 包含错误编号与错误信息的字典

4、serializer的反序列化

视图类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
from rest_framework.views import APIView from rest_framework.response import Response from .serializer import BookSerializer # 图书新增:psot 图书查询所有:get class BookView(APIView): def get(self, request): book_list = Book.objects.all() ser=BookSerializer(instance=book_list,many=True) return Response(ser.data) def post(self,request): # 反序列化---》传得是data=前端传入的数据request.data ser=BookSerializer(data=request.data) # 数据校验 if ser.is_valid(): # forms组件就这么做的 # 保存-->会报错----》需要在序列化类中重写create方法 ser.save() return Response({'msg':'新增成功','code':100}) else: print(ser.errors) return Response({'msg': '数据没有校验通过', 'code': 101}) # 图书查询一个:get ,图书修改一个:put ,图书删除一个:delete class BookDetailView(APIView): def get(self,request,pk): book = Book.objects.all().filter(pk=pk).first() ser = BookSerializer(instance=book) return Response(ser.data) def delete(self,request,pk): Book.objects.all().filter(pk=pk).delete() return Response({'code':100,'msg':"删除成功"}) def put(self,request,pk): # 修改,就有book对象,拿到要修改的对象 book=Book.objects.filter(pk=pk).first() # 使用data的数据,修改book这个对象 ser = BookSerializer(instance=book,data=request.data) if ser.is_valid(): # 会报错,需要重写序列化类的updata方法 ser.save() return Response({'code':100,'msg':"修改成功"}) else: return Response({'code': 101, 'msg': "修改失败"})

反序列化类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): # read_only=True 意思是只读,只用来做序列化,不用来做反序列化 # 如果不写read_only=True,这个字段必传,如果不传,数据校验不过 # 如果写了read_only=True,这个字段不传 id=serializers.IntegerField(read_only=True) # model中Auto,本质就是数字,IntegerField name=serializers.CharField(max_length=8,min_length=3,error_messages={'max_length':'太长了'}) # price=serializers.IntegerField() price=serializers.CharField(max_length=1000) # 写成CharField也能映射成功 def create(self, validated_data): # 代码一点没少写,甚至多了,好处解耦了,view代码少了 # validated_data就是校验过后的数据 # 高级 book=Book.objects.create(**validated_data) # 菜鸡 # name=validated_data.get('name') # price=validated_data.get('price') # book = Book.objects.create(name=name,price=price) return book # 一定要return新增的对象 def update(self, instance, validated_data): # instance 是要修改的对象 # validated_data是校验过后数据 instance.name=validated_data.get('name') instance.price=validated_data.get('price') instance.save() # 一定不要忘了保存,才存到数据库 return instance # 一定要return新增的对象

重点剖析

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
# 改了put方法和post方法 # 1 在视图类中使用 # 新增:不需要instance参数 ser=BookSerializer(data=request.data) if ser.is_valid(): ser.save() # 修改:需要instance参数 ser=BookSerializer(instance=book,data=request.data) if ser.is_valid(): ser.save() # 2 在序列化类中,必须重写create和updata,否则报 def create(self, validated_data): book=Book.objects.create(**validated_data) return book def update(self, instance, validated_data): instance.name=validated_data.get('name') instance.price=validated_data.get('price') instance.save() # 一定不要忘了保存,才存到数据库 return instance # 一定要return新增的对象 #### 每个字段有自己的校验规则##### # 数据校验---》序列化类的字段,有字段属性 # 在字段上加属性---》就会按这个属性校验 name=serializers.CharField(max_length=8,min_length=3) price=serializers.CharField(min_length=1000) # 写成CharField也能映射成功 # 拿到数据校验失败的原因 ser.errors

5、局部钩子与全局钩子

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
# 无论新增还是修改,只要执行ser.is_valid()就会触发校验 # 牢牢记住:先走字段自己的校验规则---》再走局部钩子---》再走全局钩子 # 写在序列化类中的局部钩子函数,校验单个字段 # 写在序列化类中的全局钩子函数,校验所有字段 # 局部钩子,校验书名不能以sb开头 forms组件没有,validate有 def validate_name(self,name): # name就是 要校验的字段对应的前端传入的值 if name.startswith('sb'): # 校验失败,抛异常 raise ValidationError('不能以sb开头') else: return name # 全局钩子 def validate(self, attrs): # attrs 校验过后的数据---》字段自己校验完后,局部钩子走完过的数据 name=attrs.get('name') price=attrs.get('price') # 加判断,如果通过,就返回attrs # 如果不通过就抛异常 if name == price: raise ValidationError('名字和价格不能一样') else: return attrs

6、序列化类ModelSerializer的使用

重点剖析

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
# Serializer基类,序列化类都要继承它,写字段,重写create和updata方法 # 有没有一种简单方案,不写字段了(因为字段跟表有对应关系),不写update和create了 # 原来必须要重写update和create了的原因是---》新增不知道要增加到哪个表中去 # ModelSerializer就可以完成---》跟表有对应关系---》字段不用写了,存到哪也知道,不写update和create了 # 重点: 1 class Meta: 中model和fields意思 2 给字段类加属性 extra_kwargs 3 局部全局钩跟之前没有任何区别 4 create和update不需要写了 5 可以重写某个字段,但注意缩进

序列化类的编写

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
class BookSerializer(serializers.ModelSerializer): # 要序列化的字段,没有写,但是写了model=Book,它自动把Book表中的字段映射出来,相当于 # name = serializers.CharField(max_length=32) # price = serializers.IntegerField() # 缩进关系搞懂 class Meta: model = Book # 跟Book做对应 # fields='__all__' # 序列化和反序列化Book中的所有字段 fields = ['name', 'price'] # 只序列化和反序列化某几个字段 # 重点: 如果不重写字段,但是我想给字段类加属性---》使用下面的方式 # 如果不这样写,name会默认使用model的规则max_length=32 # 如果这样写了,最大长度是8 ,最小长度是3 extra_kwargs = { 'name': {'max_length': 8, 'min_length': 3}, 'price': {'max_value': 88} } # 表示重写name这个字段,会走它的规则 # name=serializers.CharField(max_length=8,min_length=3) # 之前教的局部钩子和全局钩子完全一样,一毛一样 # 不需要重写create和update方法了,因为ModelSerializer已经写了

7、多表序列化

图书表,出版社表,作者,作者详情 (图书作者中间表)

7.1 路由

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>', views.BookDetailView.as_view()), ]

7.2 视图类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
from .models import Book,Author,AuthorDetail,Publish from rest_framework.response import Response from .serializer import BookSerializer class BookView(APIView): def get(self, request): book_list=Book.objects.all() #序列化 ser=BookSerializer(book_list,many=True) return Response(ser.data) # 反序列化的新增 def post(self,request): ser=BookSerializer(data=request.data) if ser.is_valid(): ser.save() return Response({'code':100,'msg':'新增成功'}) else: return Response({'code':101,'msg':'新增失败','err':ser.errors}) class BookDetailView(APIView): def get(self, request,pk): book=Book.objects.all().filter(pk=pk).first() ser=BookSerializer(book) return Response(ser.data) def put(self,request,pk): book = Book.objects.all().filter(pk=pk).first() ser = BookSerializer(instance=book,data=request.data) if ser.is_valid(): ser.save() return Response({'code':100,'msg':'修改成功'}) else: return Response({'code':101,'msg':'修改失败','err':ser.errors})

7.3 序列化类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
from rest_framework import serializers # 相对导入---->一个py文件中如果使用相对导入,这个文件不能以脚本运行 from .models import Book # # 绝对导入 # from app01.models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model=Book # fields="__all__" fields=['nid','name','price', 'publish_detail', 'author_list', 'publish','authors'] # depth 不要用 --->外键关联一层,我建议不要超过3 不可控,比如我们只想要某几个字段 # depth=1 extra_kwargs={ 'publish':{'write_only':True}, 'authors': {'write_only': True}, } # 方式一:重写字段+必须配合一个方法,方法返回啥,该字段就是什么--->该字段只能序列化 publish_detail=serializers.SerializerMethodField(read_only=True) def get_publish_detail(self,obj): # 就是当前 book对象 print(obj) # return obj.publish.name return {'name':obj.publish.name,'city':obj.publish.city} # 把所有的作者:作者名字和作者addr author_list=serializers.SerializerMethodField(read_only=True) def get_author_list(self,obj): # 作者有多个,先拿到所有作者,---》正向查询 author_list=[] for author in obj.authors.all(): author_list.append({'name':author.name,'addr':author.author_detail.addr}) return author_list # 方式二:在表模型models中写方法,在序列化类中写到fields中 class 表名: ... def publish_detail(self): return {'name':self.publish.name,'email':self.publish.email} 作者详情 def author_list(self): author_list=[] for author in self.authors.all(): author_list.append({'name':author.name,'addr':author.author_detail.addr}) return author_list

7.4 模型类

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) # publish_date = models.DateField(null=True) #关联关系 publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') #自动生成中间表 def __str__(self): return self.name # def publish_detail(self): # return {'name':self.publish.name,'email':self.publish.email} # 作者详情 # def author_list(self): # author_list=[] # for author in self.authors.all(): # author_list.append({'name':author.name,'addr':author.author_detail.addr}) # return author_list class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE) ''' on_delete可以选择的请情况 -models.CASCADE 级联删除 -models.SET_NULL 关联字段置为空 null=True -models.SET_DEFAULT 关联字段设为默认值 default=0 -models.DO_NOTHING 由于数据库有约束会报错,去掉外键关系(公司都不建立外键) -on_delete=models.SET(值,函数内存地址) 设置上某个值,或者运行某个函数 ''' class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name

8、请求与响应

2.1 请求

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
# django ---->请求对象----》request # django ---->响应对象----》render,HttpResponse,Redirect,JsonResponse---》本质都是HttpResponse # drf中---》请求对象----》新的request---》drf的Request类的对象 # drf的请求对象 -request.data -request.query_params -request.FILES # 控制前端传入的编码格式---》默认 :urlencoded,form-data,json # 全局生效 -项目配置文件中加入 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser', # 能够解析json 'rest_framework.parsers.FormParser', # 能够解析urlencoded 'rest_framework.parsers.MultiPartParser', #能够解析form-data ], } # 局部生效---》视图类中配置 class BookView(APIView): parser_classes = [JSONParser,] # 优先级:先找 视图类---》项目配置文件----》drf配置文件

8.2 响应

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
from rest_framework.response import Response #初始化对象,传入的参数,response对象的属性 data=None, # 要序列化的数据,字典,列表,字符串 status=None, # http响应状态码 headers=None, # 响应头---》字典 -------最重要的----- template_name=None, #模板名字---》浏览器看的时候,看到好看的页面,postman看,纯json content_type=None # 默认json格式,前后端分离项目,前端传用json,后端响应也用json格式 # 浏览器看的时候,看到好看的页面,postman看,纯json----》想控制,都是json格式,无论是浏览器还是postman # 全局生效 -项目配置文件中加入 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES':[ 'rest_framework.renderers.JSONRenderer', #json格式 'rest_framework.renderers.BrowsableAPIRenderer', #浏览器格式 ], } # 局部生效---》视图类中配置 class BookView(APIView): renderer_classes = [JSONRenderer,BrowsableAPIRenderer] # 优先级:先找 视图类---》项目配置文件----》drf配置文件

细节补充

(1) 相对导入和绝对导入

复制代码
  • 1
  • 2
# 绝对导入---》绝对指的是 环境变量 sys.path 里面的路径,项目跟路径在pycharm自动加入环境变量 # 相对导入---->一个py文件中如果使用相对导入,这个文件不能以脚本运行

(2) django国际化配置

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
# django 国际化---》配置文件改 # 国际化相关 LANGUAGE_CODE = 'zh-hans' #时区:改成东八区 TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False

(3) models 的级联删除相关

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
''' on_delete可以选择的请情况 -models.CASCADE 级联删除 -models.SET_NULL 关联字段置为空 null=True -models.SET_DEFAULT 关联字段设为默认值 default=0 -models.DO_NOTHING 由于数据库有约束会报错,去掉外键关系(公司都不建立外键) -on_delete=models.SET(值,函数内存地址) 设置上某个值,或者运行某个函数 '''

(4) 原生django,如何向响应头写数据

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
def test(request): obj=HttpResponse('ok') # obj=render() # obj=redirect('/index') # obj=JsonResponse() obj['xxx']='ooo' #直接放 return obj
posted @   马氵寿  阅读(92)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开