drf序列化组件

后台返回json数据的方式

一.自己写for循环来处理
def get(self,request):
    book_list = Book.objects.all()
    dic = [{'id':book.pk,'name':book.name} for book in book_list]
    return JsonResponse(dic,safe=False,json_dumps_params={'ensure_ascii':False})
#safe=False 可以处理列表
#json_dumps_params = {'ensure_ascii':False} 将默认编码ascii取消,使前台可以显示中文

#优点:可以自己处理字段
#缺点:单表查询ok,多表查询会复杂,无法处理时间字段


二,使用django提供的序列化组件
from django.core import serializers
ret = serializers.serialize('json',book_list)
return Httpresponse(ret)
#优点:操作简单
#缺点:不可控,将所有字段序列化,无法选择字段


三.使用drf提供的序列化组件
1.drf是一个app,使用前需在settings.py文件中设置app配置中添加'rest_framework'
2.导入
from rest_framework import serializers
from rest_framework.response import Response

3.新建myserializer.py文件,创建类继承serializers.Serializer
class BookSerializer(serializers.Serializer):
   
4.在类内部写字段(需要被序列化的字段)
 name = serializers.CharField()
    desc = serializers.CharField()
    author = serializers.CharField()


#source参数将name字段以xx显示返回给前台
xx = serializers.CharField(source='name')
#publish为外键,前台显示为对象,可以改写Publish类的__str__方法,将publish.name显示在前台,
#也可以使用source参数将publish.name赋值给publish,source参数以需序列化类的对象为基础,即book.publish.name
#可以通过book对象连表查询的数据都可以通过source返回给前台,
publish = serializers.CharField(source = 'publish.name')
#source也可以指定方法,源码以split('.')拆分成列表,for循环,是方法的话(callable)执行方法,此处将test方法的结果返回给test字段
test = serializers.CharField(source='test')


5.使用,先生成对象,需要传参数instance,instance可以是queryset对象,也可以是单个对象
instance = 'queryset对象'时需设置参数many = True,源码会对列表进行序列化
instance = '单个对象'时需设置参数many=False,源码会使用单个序列化

from book.myserializers import BookSerializer
from rest_framework.response import Response

class Query(APIView):
    def get(self,request):
        book_list = Book.objects.all()
        book_ser = BookSerializer(instance=book_list,many=True)
        #使用drf提供的Response(继承了Httpresponse)返回数据,
        return Response(book_ser.data)

6.返回字典book_ser.data #data为私有属性,实际是调用了data方法

SerializerMethodField

当返回的对象有多个时,比如一本书有多个作者
 author = serializers.CharField() 需要返回一个列表,此时需要用到SerializerMethodField()

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    desc = serializers.CharField()
    #1.定义字段
    author = serializers.SerializerMethodField()
    #2.定义对应方法,方法的返回值赋值给字段,以get_开头,才能被源码解析到
    def get_author(self,obj):
        author_list = obj.author.all()
        #这里使用了for循环
        #dic = [{'name':author.name,'phone':author.phone} for author in author_list]
        #return dic
        #也可以采用给author创建序列化类来实现
        author_ser=AuthorSerializer(instance=author_list,many=True)
        return author_ser.data
    
   
class AuthorSerializer(serlizers.Serializer):
        name = serializers.CharField()
        phone = serializers.CharField()

#优点:可控,可扩展

ModelSerializer

Serializer类并没有指明给哪个类进行序列化
使用ModelSerializer可以指明给哪个类进行序列化

from app01 import models
#继承ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        #指定表模型
        model = Book
        #指定要序列化的表字段
        fields = ['nid','name']
        #指定序列化所有字段
        #fields = '__all__'
        #指定不要序列化的表字段(不能跟fields连用)
        #exclude=['id']
        #深度,连表的深度,官方建议最多写10,个人建议3
        depth=1	
    #可以再自定义自己要序列化的字段
    publish = serializer.CharField(source='publish.name')

from book.models import *
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','desc','author']
        # depth = 1
    author = serializers.SerializerMethodField()
    #注意:自定义的字段必须在fields中定义,否则报错
    def get_author(self, obj):
        author_list = obj.author.all()
        author_ser = AuthorSerializer(instance=author_list, many=True)
        return author_ser.data
    # publish = serializers.CharField(source='publish.name')

序列化单个对象

class Book(APIView):
    def get(self,request,id,*args,**kwargs):
        book = models.Book.objects.filter(pk=id).first()
        #单个对象,many=False,instance必须是单个对象,而不是querset对象(都是列表)
        book_ser = BookSerializer(instance=book,many=False)
        return Response(book_ser.data)

反序列化组件


class Books(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        book_ser = BookSerializer(instance=book_list, many=True)
        return Response(book_ser.data)

    def post(self, request):
        res = {"staus":100,"msg":"新增成功","data":[]}
`
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            res["data"] =book_ser.data
        else:
            res["msg"]="新增失败"
            res["data"] = book_ser.errors
        return Response(res)
        # 没有继承ModelSerializer无法使用save,因为不确定保存给哪个表

局部钩子


函数名称:validate_字段名
触发条件:字段名校验通过了,才会触发局部钩子
from book.models import *
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','desc','author']
        # depth = 1
    author = serializers.SerializerMethodField()

    def get_author(self, obj):
        author_list = obj.author.all()
        author_ser = AuthorSerializer(instance=author_list, many=True)
        return author_ser.data
    # publish = serializers.CharField(source='publish.name')

    def validate_name(self,value):
        print(0)
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

全局钩子

函数名称:validate
触发条件:局部钩子通过后才会触发

from book.models import *
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','desc','author']
        # depth = 1
    author = serializers.SerializerMethodField()

    def get_author(self, obj):
        author_list = obj.author.all()
        author_ser = AuthorSerializer(instance=author_list, many=True)
        return author_ser.data
    # publish = serializers.CharField(source='publish.name')

    def validate_name(self,value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

    def validate(self, attrs):
        publish =attrs.get('publish')
        if not publish:
            raise ValidationError('不能为空')
        return attrs

更新对象put方法

 def put(self, request, id, *args, **kwargs):
        res = {"staus": 100, "msg": "更新成功", "data": []}
        book = models.Book.objects.filter(pk=id).first()
        #更新的时候,反序列化内加入instance参数,保存的时候不需要instance
        book_ser = BookSerializer(data=request.data,instance=book)
        #进行save操作前必须判断是否通过校验,执行.is_valid才会去校验字段
        if book_ser.is_valid():
            book_ser.save()
            res["data"]= {"name":book.name,'desc':book.desc}
        else:
            res["msg"] = "更新失败"
            res["data"] = book_ser.errors
        return Response(res)
原文地址:https://www.cnblogs.com/robert-zhou/p/10601063.html