drf之序列化类

发布时间 2023-12-20 22:47:53作者: jntmwl

序列化类介绍

1 序列化  qs对象,单个对象 做序列化给前端
2 反序列化数据校验:前端传入数据---》校验数据是否合法
3 反序列化---》前端传入数据,存到数据库中
# 因为咱么在写接口时,需要序列化,需要反序列化,而且反序列化的过程中要做数据校验---》drf直接提供了固定的写法,只要按照固定写法使用,就能完成上面的三个需求

# 提供了两个类 Serializer ModelSerializer
	-以后咱们只需要写自己的类,继承drf提供的序列化类,使用其中的某些方法,就能完成上面的操作
    
    
    
# 使用APIView+序列化类+Response 完成接口的编写

快速使用

# 上面做序列化,是自己for拼的
# 上面做反序列化,自己写的
# 没有做数据校验


########  drf 提供的序列化器,实现 序列化,反序列化  和   数据校验  #####


# 使用步骤:
    1 写个py文件,叫serializer.py
    2 写个类,继承serializers.Serializer
    3 在类中写要序列化的字段
    class PublishSerializer(serializers.Serializer):
        # 写字段,要序列化的字段
        name = serializers.CharField()
        addr = serializers.CharField()
        id = serializers.IntegerField()
        
    4 在视图类中使用,完成  序列化
    	-多条
        	-ser = PublishSerializer(instance=publish_list, many=True)  	
            -ser.data  序列化后的数据
        -单条:
        	-ser = PublishSerializer(instance=publish)  	
            -ser.data  序列化后的数据

1.1 序列化类基本使用,序列化多条(使用方式类似forms组件)

serializer.py--BookSerializer类

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    # price = serializers.CharField()
    publish = serializers.CharField()

views.py--->BookView类

ps:我们在编写post请求添加数据的时候,需要注意,我们需要在serializer.py编写的BookSerializer类中添加一个create函数(不加他会报错,报错信息中的提示就是缺一个create函数,导致报错的原因是调用save的时候用到了create)

class BookView(APIView):
    def get(self, request):
        # 只是为了验证之前讲过的
        print(request.method)
        print(request._request)
        print(type(self.request))

        books = Book.objects.all()
        # 使用序列化类来完成---》得有个序列化类
        # instance要序列化的数据books queryset对象
        # many=True 只要是queryset对象要传many=True,如果是单个对象就不用传
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)  # 无论是列表还是字典都可以序列化

    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
            ser.save()  # 调用ser.save,自动触发咱们写的create,保存起来
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
]

1.2 序列化单条

序列化类---没有动

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    # price = serializers.CharField()
    publish = serializers.CharField()

视图类---》BookDetailView

class BookDetailView(APIView):
    # def get(self, request,pk):
    def get(self, request, *args, **kwargs):
        book = Book.objects.filter(pk=kwargs.get('pk')).first()
        # 序列化
        ser = BookSerializer(instance=book)
        return Response(ser.data)

url加了新的路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetaView.as_view()),
]

二、反序列化(重点)

2.1 反序列化的新增

序列化类

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定要返回新增的对象
        return book

视图类

class BookView(APIView):
    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
            ser.save()  # 调用ser.save,自动触发咱们写的create,保存起来
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

2.2 反序列化的修改

序列化类

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定不要返回新增的对象
        return book

    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库

        return instance  # 不要忘了吧修改后的对象,返回

视图类

class BookDetailView(APIView):


    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        # 反序列化保存 ---借助于序列化类
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()  # 由于没有重写update,所以这报错
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

2.3 删除单条

视图类

class BookDetailView(APIView):

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

三、完整的代码

models.py

from django.db import models


# Create your models here.


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

urls.py

from django.db import models


# Create your models here.


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

views.py

from django.shortcuts import render

# # rest_framework很规范,想导入什么拼写单词即可
# from rest_framework.request import Request
# from rest_framework.response import Response

from rest_framework.views import APIView
from django.http import JsonResponse  # 原生的
from rest_framework.response import Response  # drf提供的
from .models import Book

# 1  基于APIView+JsonResponse 写接口
# class BookView(APIView):
#     def get(self, request):
#         books = Book.objects.all()
#         book_list = []
#         for book in books:
#             book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
#
#         return JsonResponse(book_list, safe=False)

# 基于APIView+Response 写接口
# class BookView(APIView):
#     def get(self, request):
#
#         print(request.GET)
#
#
#         books = Book.objects.all()
#         book_list = []
#         for book in books:
#             book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
#
#         return Response(book_list)  # 无论是列表还是字典都可以序列化


# APIView和Response 之前没有用过


#  基于APIView+序列化类+Response 写接口
from .serializer import BookSerializer


class BookView(APIView):
    def get(self, request):
        # 只是为了验证之前讲过的
        print(request.method)
        print(request._request)
        print(type(self.request))

        books = Book.objects.all()
        # 使用序列化类来完成---》得有个序列化类
        # instance要序列化的数据books queryset对象
        # many=True 只要是queryset对象要传many=True,如果是单个对象就不用传
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)  # 无论是列表还是字典都可以序列化

    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
            ser.save()  # 调用ser.save,自动触发咱们写的create,保存起来
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(APIView):
    # def get(self, request,pk):
    def get(self, request, *args, **kwargs):
        book = Book.objects.filter(pk=kwargs.get('pk')).first()
        # 序列化
        ser = BookSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        # 反序列化保存 ---借助于序列化类
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()  # 由于没有重写update,所以这报错
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

serializer.py(在app01中创建一个新的py文件写即可)

# from rest_framework.serializers import Serializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import Book


class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定不要返回新增的对象
        return book

    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库

        return instance  # 不要忘了吧修改后的对象,返回

    # 反序列化校验的局部钩子 ,名字不能以sb开头
    def validate_name(self, name):
        # 校验name是否合法
        if name.startswith('sb'):
            # 校验不通过,抛异常
            raise ValidationError('不能以sb开头')
        else:
            return name

    # 全局钩子
    def validate(self, attrs):
        # 校验过后的数据,书名跟出版社名字不能一致
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError('书名跟出版社名字不能一致')
        else:
            return attrs

四、反序列化的校验

# 序列化类反序列化,数据校验功能--->类比forms组件
	-局部钩子
    -全局钩子
class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定不要忘了返回新增的对象
        return book

    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库

        return instance  # 不要忘了吧修改后的对象,返回

    # 反序列化校验的局部钩子 ,名字不能以sb开头
    def validate_name(self, name):
        # 校验name是否合法
        if name.startswith('sb'):
            # 校验不通过,抛异常
            raise ValidationError('不能以sb开头')
        else:
            return name

    # 全局钩子
    def validate(self, attrs):
        # 校验过后的数据,书名跟出版社名字不能一致
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError('书名跟出版社名字不能一致')
        else:
            return attrs
        
       # -全局钩子--》前端多传的,这里不会有
	    def validate(self, attrs):
            print(attrs)
            # 多个字段同时校验
            # 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样
            if attrs.get('name')[:3] == attrs.get('addr')[:3]:
                raise ValidationError('出版社名和地址不能一样')
            return attrs
        
        
 # 使用步骤
	-写序列化类:写三层规则
    -视图类中:
        ser = PublishSerializer(data=request.data)  # 把待校验数据传入
        if ser.is_valid():  # 做数据校验---》三层
            print(ser.data)
        else:
            print(ser.errors)  # 没有校验通过,打印错误信息

五、序列化类保存

# 使用步骤:
	1 在序列化类中,必须重写 create,完成真正的保存
       # 保存,必须重写create
        def create(self, validated_data):
            # validated_data 校验过后的数据---》多传的数据,在这没有
            publish = Publish.objects.create(**validated_data)
            return publish  # 不要忘了返回新增的对象---》后续会拿着这个对象做序列化  ser.data--->根据它做序列化的
    2 在视图类中,数据校验通过后,调用ser.save()
     ser.save()  # 使用序列化类保存--》会报错---》咱们没有指定保存到那个表--》必须重写create方法
        
        
        
        
        
# 修改功能,也要校验和保存

# 修改使用步骤
	1 在序列化类中,必须重写 update,完成真正的修改
        def update(self, instance, validated_data):  # {name:上海出版社,add:上海地址}
            instance.name=validated_data.get('name')
            instance.addr=validated_data.get('addr')
            instance.save() # publish 对象的save---》保存到数据中
            return instance
   2 视图类中
		ser = PublishSerializer(instance=publish, data=request.data)
		ser.save() # 虽然新增或修改都是调用save,但是内部做了判断