DRF---序列化类Serializer的反序列化,局部和全局钩子和序列化类ModelSerializer的使用

序列化类Serializer的反序列化


使用drf的APIView写5个接口

from rest_framework.views import APIView
# 图书新增:psot  图书查询所有:get
class BookView(APIView):
    def get(self, request):
        books = []
        book_list = Book.objects.all()
        for book in book_list:
            books.append({'id':book.id,'name': book.name, 'price': book.price})
        return JsonResponse(books, safe=False,json_dumps_params={'ensure_ascii':False})
    def post(self,request):
        # 前端传入的,继承了APIView
        name=request.data.get('name')
        price=request.data.get('price')
        # 存到表中
        book=Book.objects.create(name=name,price=price)
        # return JsonResponse({'id':book.id,'name':book.name,'price':book.price})
        return JsonResponse({'msg':'新增成功','code':100})
# 图书查询一个:get  ,图书修改一个:put  ,图书删除一个:delete
class BookDetailView(APIView):
    def get(self,request,pk):
        book = Book.objects.all().filter(pk=pk).first()
        return JsonResponse({'id':book.id,'name':book.name,'pirce':book.price})
    def delete(self,request,pk):
        Book.objects.all().filter(pk=pk).delete()
        return JsonResponse({'code':100,'msg':"删除成功"})


    def put(self,request,pk):
        book=Book.objects.all().filter(pk=pk).first()
        book.price=request.data.get('price')
        book.name=request.data.get('name')
        book.save()

        return JsonResponse({'code':100,'msg':"修改成功"})

使用APIView+序列化类(序列化:查单个,查所有)+Response来写5个接口

'''序列化类'''
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也能映射成功
'''视图类'''
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):
        # 前端传入的,继承了APIView
        name=request.data.get('name')
        price=request.data.get('price')
        # 存到表中
        book=Book.objects.create(name=name,price=price)
        # return JsonResponse({'id':book.id,'name':book.name,'price':book.price})
        return Response({'msg':'新增成功','code':100})
# 图书查询一个: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.objects.all().filter(pk=pk).first()
        book.price=request.data.get('price')
        book.name=request.data.get('name')
        book.save()

        return Response({'code':100,'msg':"修改成功"})

使用APIView+序列化类(序列化:查单个,查所有 反序列化:新增一个,修改一个)+Response来写5个接口

'''序列化类'''
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新增的对象

'''**视图类**'''
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': "修改失败"})

重点总结:改了put方法和post方法

  1. 在视图类中使用

     # 新增
       ser=BookSerializer(data=request.data)
       if ser.is_valid(): 
           ser.save()
      # 修改
       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 

局部和全局钩子


无论新增还是修改,只要执行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

序列化类ModelSerializer的使用


Serializer基类,序列化类都要继承它然后就是写字段,重写create和updata方法。有没有一种简单方案,不写字段了(因为字段跟表有对应关系),不写update和create了。

原来必须要重写update和create了的原因是因为新增不知道要增加到哪个表中去。

ModelSerializer就可以解决这个问题,跟表有对应关系,字段不用写了,存到哪也知道,不写update和create了。

重点:

  1. class Meta: 中model和fields意思(model对应的表,fields对应的字段)
  2. 给字段类加属性 extra_kwargs
  3. 局部全局钩跟之前没有任何区别
  4. create和update不需要写了
  5. 可以重写某个字段,但注意缩进
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已经写了
posted @ 2022-06-15 16:11  早安_1207  阅读(108)  评论(0)    收藏  举报
返回顶端