# 作用: 1. 序列化,序列化器(类)会把模型对象(Book对象,Queryset对象)转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request以后变成字典(request.data),序列化器(类)可以把字典转成模型 3. 反序列化,完成数据校验功能 # 本质: 就是写一个类继承一个类 可以完成序列化,反序列化和数据校验
准备:
# 因为他的目的就是序列化与反序列化,所以建议把它建立在一个单独的py文件下。 # 这里新建使用 serializer.py(见明知意)
具体使用:
models.py创建一个模型表
from django.db import models class BOOKS(models.Model): name = models.CharField(max_length=32) price = models.IntegerField() publish = models.CharField(max_length=32)
serializer.py序列化类
from rest_framework import serializers # 创建序列化类继承Serializer,目的:序列化和反序列化Book表 class BookSerializer(serializers.Serializer): # 对应字段(要序列化,反序列化的字段) name = serializers.CharField(这里可以写校验数据校验规则(相当于forms组件)) price = serializers.IntegerField() publish = serializers.CharField()
urls.py
urlpatterns = [ path('books/',views.BookAPIView.as_view()), ] # 通过books/路由访问BookAPIView视图类
views.py
from rest_framework.views import APIView from rest_framework.response import Response from app01 import models from .serializer import BookSerializer # 导入序列化类来使用 # 查询多个数据接口 class BookAPIView(APIView): # 查询数据是get请求的结果 def get(self,request,*args,**kwargs): # 查询book表中所有字段数据 book_list = models.BOOKS.objects.all() # 序列化过程,把queryset转换成字典 # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True ser = BookSerializer(instance=book_list,many=True) # 可使用关键字传参 # ser = BookSerializer(book_list,many=True) # 可使用位置传参 # 将数据返回(此时数据是字典形式,返回到前端则是json格式数据,这是Response帮我们完成的,serializer序列化是将queryset对象转换为字典的形式。) return Response(ser.data)
操作单条数据:
需重写路由:
urlpatterns = [ path('books/',views.BookAPIView.as_view()), # 操作单个数据(使用转换器传入pk值操作单条数据) path('books/<int:pk>',views.BookDetailAPIView.as_view()) ]
# 查询单个: class BookDetailAPIView(APIView): def get(self,request,pk): book = models.BOOKS.objects.filter(pk=pk).first() # 序列化单个数据就不需要添加many=True参数 ser = BookSerializer(book) return Response(ser.data) # 删除单个: # 发送delete请求 class BookDetailAPIView(APIView): def delete(self,request,pk): # 删除数据无需序列化与反序列化直接删除即可 models.BOOKS.objects.filter(pk=pk).delete() # 删除成功返回一个空,如果没删除成功会自己抛异常返回一个空 return Response() # 修改单个: # 发送put请求 class BookDetailAPIView(APIView): def put(self,request,pk): book = models.BOOKS.objects.filter(pk=pk).first() # 修改数据是我们自己写json格式数据,然后传给后端,所以需要反序列化 # 第一个参数填写需要修改的值,第二个参数(data)填写用户上传的新的值 ser = BookSerializer(instance=book,data=request.data) # 校验数据 if ser.is_valid(): ser.save() return Response(ser.data)
新增单个:
class BookAPIView(APIView): def post(self,request,*args,**kwargs): ser = BookSerializer(data=request.data) # 如果要新增就不需要传instance if ser.is_valid(): ser.save() return Response(ser.data)
特别注意:
修改和新增需要重写create与updata方法
# 在编写新增与修改功能的时需要在serializer的类中重写create()与updata()方法 # 不然会报错:因为不重写不知道保存在那张表中。 def update(self, instance, validated_data): # instance就是book对象 validated_data校验通过的数据 instance.name = validated_data.get('name') instance.price = validated_data.get('price') instance.publish = validated_data.get('publish') # 保存(book对象所有的save方法) # 通过表对象保存,这样就知道了保存到那张表中 instance.save() # 返回 return instance def create(self, validated_data): # validated_data为用户上传的数据 book = models.BOOKS.objects.create(**validated_data) # 打散保存 # 通过表对象保存,这样就知道了保存到那张表中 # 返回 return book
引子:
# 那么如果想要使用别的字段名,那么这里就需要使用到source # source的作用:可以对应表模型的字段和方法(返回结果是什么,字段就是什么)
source基本使用:
class BookSerializer(serializers.Serializer): # source参数编写对应表模型的字段名(想与那个字段做对应) book_name = serializers.CharField(source='name')
# source也可以对应表模型中的方法(方法的返回结果是什么,字段对应的结果就是什么) class BOOKS(models.Model): name = models.CharField(max_length=32) price = models.IntegerField() publish = models.CharField(max_length=32) def get_book_name(self): return '经典名著'+self.name class BookSerializer(serializers.Serializer): # source编写方法名,返回方法的返回结果 book_name = serializers.CharField(source='get_book_name')
# 放法2:不使用source方法 class BookSerializer(serializers.Serializer): get_book_name = serializers.CharField()
使用场景:
urls.py
path('books/',views.BookAPIView.as_view()),
models.py
class BOOKS(models.Model): name = models.CharField(max_length=32) price = models.IntegerField() publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING) class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32)
serializer.py
from rest_framework import serializers from app01 import models class BookSerializer(serializers.Serializer): # 写字段(要序列化,反序列化的字段) name = serializers.CharField() price = serializers.IntegerField() publish = serializers.CharField()
views.py
from rest_framework.response import Response from app01 import models from .serializer import BookSerializer class BookAPIView(APIView): def get(self,request,*args,**kwargs): # 查询book表中所有字段的对应关系 book_list = models.BOOKS.objects.all() # 序列化过程,把queryset转换成字典 # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True ser = BookSerializer(book_list,many=True) # 将数据返回 print(ser.data) return Response(ser.data)
运行结果:
# 那么我们如何拿到关联表所有字段的值(拿到出版社的详细信息)呢? # 方式一:我们也可以使用上述的方法 # 如下:我们可以看到该方法非常的古怪,没有人会这样使用。
# 方式二:使用source方法实现
# 方式三:不使用source直接写对应方法名
# 方式四:使用SerializerMethodField()方法不需要在表模型中写方法,在序列化类中编写 # 使用使用SerializerMethodField就必须指定一个get_字段名的方法 # 如果字段名不一致则报错 # 该字段名是SerializerMethodField方法需要序列化的字段
source主要作用:就是用来做一对多,多对多的字段返回。
# urls.py path('publish/',views.PublishAPIView.as_view()), # serializer.py class PublishSerializer(serializers.Serializer): # 写字段(要序列化,反序列化的字段) name = serializers.CharField(max_length=8,min_length=3) # 编写数据校验规范 addr = serializers.CharField(max_length=8,min_length=3) # 重写新增功能 def create(self, validated_data): # validated_data为用户上传的数据 publish = models.Publish.objects.create(**validated_data) # 打散保存 # 返回 return publish # views.py class PublishAPIView(APIView): def get(self,request,*args,**kwargs): # 查询book表中所有字段的对应关系 publish_list = models.Publish.objects.all() # 序列化过程,把queryset转换成字典 # 第一个参数是需要序列化的对象,如果序列化多条数据,一定要加上many=True ser = PublishSerializer(publish_list,many=True) # 将数据返回 return Response(ser.data) def post(self,request,*args,**kwargs): ser = PublishSerializer(data=request.data) # 如果要新增就不需要传instance # 校验数据是否通过 if ser.is_valid(): ser.save() return Response(ser.data) else: return Response({'msg':'出错'})
# 局部钩子 def validate_name(self,name): if name.startswith('sb'): # 抛异常 raise ValidationError("不能以sb开头") else: return name
# 全局钩子 def validate(self, attrs): # attrs存放的就是request.data的数据 name=attrs.get('name') addr=attrs.get('addr') return attrs
# 创建模型类序列化类需要继承 serializers.ModelSerializer # 如果想要使用该序列化器记得修改views.py视图层函数 # create和update不需要重写,它帮我们封装好了 # 创建模型类序列化器 class PublishModelSerializer(serializers.ModelSerializer): class Meta: # 这里就不需要写对应的字段,直接写对应的表即可 model = models.Publish # 对应Publish表 fields = ['id','name'] # 序列化哪些字段 (只序列化id,name字段) fields = '__all__' # 序列化全部字段 fields = ['id','publish_detail'] # 也可序列化模型类中的方法 exclude = ['id'] # 除了id字段其他都序列化(但不会存在方法) # 创建模型类序列化器 class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.BOOKS fields = '__all__' depth = 1 # 深度:深一层(外键深入的意思) 非常耗费效率,不能控制深入后想要查询的字段,不建议使用,写多层不会报错,有几层就深入几层
参数总结:
fields = ['id','name'] # 序列化哪些字段 (只序列化id,name字段) fields = '__all__' # 序列化全部字段 fields = ['id','publish_detail'] # 也可序列化模型类中的方法 exclude = ['id'] # 除了id字段其他都序列化(但不会存在方法) depth = 1 # 深度:深一层(外键深入的意思) 非常耗费效率,不能控制深入后想要查询的字段,不建议使用,写多层不会报错,有几层就深入几层
重写字段:
# 重写字段SerializerMethodField和初始序列化类使用方法一样 name = serializers.SerializerMethodField() def get_name(self,obj): return '出版社:'+obj.name
添加字段:
# 添加字段和初始化序列化类使用方法一样 publish_detail = serializers.CharField(source='publish_detail')
字段校验映射:
# 自己的字段校验规则:映射了表模型的规则(如果校验失败则同样会添加到ser.errors错误信息中)
局部钩子与全局钩子:
# 与初始序列化类使用方法完全一致 # 局部钩子 def validate_name(self,name): if name.startswith('sb'): # 抛异常 raise ValidationError("不能以sb开头") else: return name # 全局钩子 def validate(self, attrs): # attrs存放的就是request.data的数据 name=attrs.get('name') addr=attrs.get('addr') return attrs
write_only()与read_only()方法
### write_only只写 反序列化时候使用,序列化的时候不用 ### read_only只读 序列化的时候使用,反序列化的时候不用 # 使用场景 # 新增字段 # 读的时候只读name_detail字段 name_detail = serializers.SerializerMethodField(read_only=True) def get_name_detail(self,obj): return '新增'+obj.name # name字段只写,此时的name字段在__all__里(现在已经不能读了因为只限制可以写) name = serializers.CharField(write_only=True)
额外给字段添加参数:
# 上述这样如果有很多字段需要限制只读只写参数的话非常的麻烦 # 需要编写在class META:类中 # 额外给字段传递额外参数关键字:extra_kwargs extra_kwargs = {'name': {'write_only': True}} # 相当于:name = serializers.CharField(write_only=True)