02 DRF之ModelSerializer
一、Django序列化方法
Django序列化方法一,使用Values和JsonResponse来实现
弊端:需要自己处理外键
def get(self,request): book_list=Book.objects.values("id","title","pub_time","publisher") # queryset无法直接被json系列化,先对其list book_list=list(book_list) ret=[] for book in book_list: publisher_id=book["publisher"] publisher_obj=Publisher.objects.filter(id=publisher_id).first() book["publisher"]={"id":publisher_id,"title":publisher_obj.title} ret.append(book) # ensure_ascii=False避免中文乱码 # ret=json.dumps(book_list,ensure_ascii=False) # return HttpResponse(ret) return JsonResponse(ret,safe=False,json_dumps_params={"ensure_ascii":False})
Django serializers实现序列化
弊端:外键任然以主键的方式存在,且有其他前端无用的字段
def get(self,request): book_list=Book.objects.all() ret=serializers.serialize("json",book_list,ensure_ascii=False) return HttpResponse(ret)
二、组件djangorestframework序列化
1、安装djangoresuframework
2、在APP中注册rest_framework应用
3、创建自己的serializers模块,在模块中创建model对应的Serializer类
from rest_framework import serializers class BookSerializer(serializers.Serializer): id=serializers.IntegerField() title=serializers.CharField(max_length=64) CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) category=serializers.ChoiceField(choices=CHOICES,source="get_category_display") pub_time=serializers.DateField()
4、在视图模块中导入模块对应的Serializer类,从rest_framework.views中导入APIView,从rest_framework.response中导入Response
5、创建视图类,继承APIView,返回Response类,被序列化的数据在对应类Serializer().data中
from rest_framework.views import APIView from rest_framework.response import Response from DRFServer.serializers import BookSerializer class BookView(APIView): def get(self,request): # book_obj=Book.objects.first() # 一条数据 # ret=BookSerializer(book_obj) book_list=Book.objects.all() # 多条数据 ret=BookSerializer(book_list,many=True) return Response(ret.data)
6、外键采用嵌套类得方式,ManyToMany字段添加many=True参数
from rest_framework import serializers 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=64) CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) category=serializers.ChoiceField(choices=CHOICES,source="get_category_display") pub_time=serializers.DateField() publisher=PublisherSerializer() # many=True表示ManyToMany author=AuthorSerializer(many=True)
7、Choice字段,需添加source属性,字段为category,source属性值为get_category_display,字段为go,source属性值为get_go_display
三、DRF反序列化
对前端上传得数据进行反序列化。
1、对Serializer字段进行修改,添加相关属性
required=False:id字段无需上传,也就无需验证,添加required属性
read_only=True:该字段只在序列化时使用,反序列化忽略
write_only=True:该字段只在反序列化时使用,序列化时忽略。字段名称需要和前端沟通,需一一对应。
2、在对应Serializer类中添加create方法,对验证过来的数据通过ORM进行保存,注意字段名称
class BookSerializer(serializers.Serializer): id=serializers.IntegerField(required=False)#required=False标示不验证 title=serializers.CharField(max_length=64) CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) #read_only=True只在序列化的时候使用, category=serializers.ChoiceField(choices=CHOICES,source="get_category_display", read_only=True) # w_category和前端沟通好的字段,前端上传w_category,且write_onle=True,标示是反序列化字段 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) pub_time=serializers.DateField() #只在序列化时使用 publisher=PublisherSerializer(read_only=True) #前端回传publisher_id字段,只反序列化使用 publisher_id=serializers.IntegerField(write_only=True) # many=True表示ManyToMany,只在序列化时使用 author=AuthorSerializer(many=True,read_only=True) #author_list字段用于前端上传作者id,只反序列化使用 author_list=serializers.ListField(write_only=True) def create(self, validated_data): book=Book.objects.create(title=validated_data['title'], category=validated_data['w_category'], pub_time=validated_data['pub_time'], publisher_id=validated_data["publisher_id"]) book.author.add(*validated_data['author_list']) return book
3、在View视图中添加post方法,用户数据存储在request.data中
4、实例化对应的Serializer,并传入data
5、对数据进行验证,使用serializer.is_valid(),验证通过进行数据保存并返回用户提交的数据,验证失败返回Response(serializer.errors)
class BookView(APIView): def get(self,request): pass def post(self,request): serializer=BookSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.validated_data) else: return Response(serializer.errors)
四、DRF的PUT请求验证部分字段
用户针对某个资源发送put请求,以更新资源
1、在url中添加路由,注意参数id
2、创建对应的视图类,定义put方法
from django.shortcuts import render from django.http import HttpResponse,JsonResponse from django.core import serializers from DRFServer.models import Book,Publisher import json # Create your views here. from django.views import View from rest_framework.views import APIView from rest_framework.response import Response from DRFServer.serializers import BookSerializer # class BookView(View): # 版本一,使用values和JsonResponse实现序列号 # def get(self,request): # book_list=Book.objects.values("id","title","pub_time","publisher","author") # # queryset无法直接被json系列化,先对其list # book_list=list(book_list) # ret=[] # for book in book_list: # publisher_id=book["publisher"] # publisher_obj=Publisher.objects.filter(id=publisher_id).first() # book["publisher"]={"id":publisher_id,"title":publisher_obj.title} # ret.append(book) # # ensure_ascii=False避免中文乱码 # # ret=json.dumps(book_list,ensure_ascii=False) # # return HttpResponse(ret) # return JsonResponse(ret,safe=False,json_dumps_params={"ensure_ascii":False}) # 版本二,使用django serializers实现序列号 # def get(self,request): # book_list=Book.objects.all() # ret=serializers.serialize("json",book_list,ensure_ascii=False) # return HttpResponse(ret) class BookView(APIView): def get(self,request): # book_obj=Book.objects.first() # 一条数据 # ret=BookSerializer(book_obj) book_list=Book.objects.all() # 多条数据 ret=BookSerializer(book_list,many=True) return Response(ret.data) def post(self,request): serializer=BookSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.validated_data) else: return Response(serializer.errors) class BookEditView(APIView): def get(self,request,id): book_obj=Book.objects.filter(id=id).first() ret=BookSerializer(book_obj) return Response(ret.data) def put(self,request,id): data=request.data book_obj = Book.objects.filter(id=id).first() # partial=True允许部分更新 serializers=BookSerializer(instance=book_obj,data=data,partial=True) if serializers.is_valid(): # 方式一 # serializers.update(book_obj,serializers.validated_data) #方式二 serializers.save() return Response(serializers.validated_data) else: return Response(serializers.errors)
a、拿到资源的query对象
b、创建serializers实例,传入instance(query对象),data(用户put的数据),partial(True标示允许部分更新)参数,并对数据进行验证
c、验证过后调用实例的save方法,或者调用update方法,注意,update方法需要传入对象实例和验证后的数据
d、验证失败返回Response(serializers.errors)
3、在定义的Serializer类中添加update方法,接收instance和validated_data,并通过ORM方法对数据进行更新,更新完成调用save方法,并返回实例
# _*_ coding:utf-8 _*_ # Author:huangmingya # DateTime: 2019/6/24 11:03 from rest_framework import serializers from DRFServer.models import * 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(required=False)#required=False标示不验证 title=serializers.CharField(max_length=64) CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) #read_only=True只在序列化的时候使用, category=serializers.ChoiceField(choices=CHOICES,source="get_category_display", read_only=True) # w_category和前端沟通好的字段,前端上传w_category,且write_onle=True,标示是反序列化字段 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) pub_time=serializers.DateField() #只在序列化时使用 publisher=PublisherSerializer(read_only=True) #前端回传publisher_id字段,只反序列化使用 publisher_id=serializers.IntegerField(write_only=True) # many=True表示ManyToMany,只在序列化时使用 author=AuthorSerializer(many=True,read_only=True) #author_list字段用于前端上传作者id,只反序列化使用 author_list=serializers.ListField(write_only=True) def create(self, validated_data): book=Book.objects.create(title=validated_data['title'], category=validated_data['w_category'], pub_time=validated_data['pub_time'], publisher_id=validated_data["publisher_id"]) book.author.add(*validated_data['author_list']) return book def update(self, instance, validated_data): instance.title=validated_data.get("title",instance.title) instance.category=validated_data.get("w_category",instance.category) instance.pub_time=validated_data.get("pub_time",instance.pub_time) 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
5、DRF数据类容验证
自定义验证字段,优先于钩子函数验证
1、验证器内部使用局部钩子函数验证指定字段,使用validate_字段名方法验证指定字段
2、全局钩子验证字段,使用validate方法
3、自定义验证方法,可以作用于多个字段
在字段中添加validators属性,接收一个列表,列表中是方法名