序列化组件的初步使用、序列化类中的高级用法source、高级用法定制字段、高级用法定制字段、反序列化校验总结

一 序列化组件的初步使用

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

路由

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

序列化类

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.IntegerField()
    publish = serializers.CharField()

    # 重写 create() 方法
    # validated_data 是前端传入校验之后的数据
    def create(self, validated_data):
        # 注意:在这里要注意在前端传入的 key 必须与数据库的字段保持一致,否则是添加不成功的
        book = Book.objects.create(**validated_data)
        return book

    # 重写update()
    def update(self, instance, validated_data):
        # instance 是待修改的对象
        # validated_data 是校验过后的数据,是个字典

        # 方式1:
        # instance.name = validated_data.get('name')
        # instance.price = validated_data.get('price')
        # instance.publish = validated_data.get('publish')
        # instance.save()
        # return instance

        # 方式2:推荐使用
        # 方式2: 反射是通过字符串动态的获取或设置属性或方法
        for key in validated_data:  # {"name":"西游记", "price":99, "publish":"老男孩出版社"}
            # 把k,v放入instance对象中,通过反射修改
            setattr(instance, key, validated_data.get(key))
            # 类似于 instance.name = validated_data.get('name') 这种修改数据

        # 放入instance中后,记得保存
        instance.save()
        return instance

视图函数

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializer import BookSerializer


class BookView(APIView):
    # 查询所有接口
    def get(self, request, *args, **kwargs):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

    # 新增一条
    def post(self, request, *args, **kwargs):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()  # 要在序列化类中重写create(),否则会报错
            return Response({'code': 100, 'msg': '添加成功', 'data': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(APIView):
    # 查询一条
    def get(self, request, pk, *args, **kwargs):
        book = Book.objects.all().filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response({'code': 100, 'msg': f'id为{pk}的数据查询成功', 'data': ser.data})

    def put(self, request, pk, *args, **kwargs):
        # 方式1:推荐使用
        # # 要用查询出来的数据,使用传入的数据,做修改
        book = Book.objects.filter(pk=pk).first()
        # 使用前端传入的数据,修改book
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 要在序列化类中重写update(),否则会报错
            # 这是调用序列化类的 save() 才会触发 update() 方法的执行,不是 book.save()
            ser.save()
            return Response({'code': 100, 'msg': '数据修改成功', 'data': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

        # 方式2:
        # from rest_framework import status
        # 
        # book = Book.objects.filter(pk=pk).first()
        # if not book:
        #     return Response({'code': 101, 'msg': '书籍不存在'}, status=status.HTTP_404_NOT_FOUND)
        # 
        # field_to_update = request.data.get('field_to_update')  # 获取要更新的字段名
        # new_value = request.data.get('new_value')  # 获取新值
        # 
        # ser = BookSerializer(instance=book)
        # 
        # if field_to_update:
        #     if field_to_update not in ser.fields:
        #         return Response({'code': 101, 'msg': '要更新的字段不存在'}, status=status.HTTP_400_BAD_REQUEST)
        #     setattr(book, field_to_update, new_value)
        # else:
        #     ser = BookSerializer(instance=book, data=request.data)
        #     if not ser.is_valid():
        #         return Response({'code': 101, 'msg': ser.errors}, status=status.HTTP_400_BAD_REQUEST)
        #     ser.save()
        # 
        # return Response({'code': 100, 'msg': '数据修改成功', 'data': BookSerializer(instance=book).data})

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

总结序列化和反序列化

# 1 序列化类---》做序列化
	-多条一定要写  many = True
    
# 2 序列化校验:
	ser.is_valid()  就会走校验
    
# 4 反序列化保存
	-新增:
    	ser = BookSerializer(data=request.data)
        ser.save()--->触发 序列化类中的 create---》为什么?内部做了判断:根据是否有instance
        create中,自己写保存到哪个表中:有数据--》保存到某个表中
    -修改
    	ser = BookSerializer(instance=待修改对象,data=request.data)
        ser.save()--->触发 序列化类中的 update---》为什么?内部做了判断:根据是否有instance
        update中,有待修改对象,有数据---》修改完保存即可--》两种方式

二 序列化类中的高级用法source

# 字段类的属性
# 如下写法,就能修改序列化的字段
class BookSerializer(serializers.Serializer):
    # 用法一:最简单,拿表中的字段
    xxx = serializers.CharField(source='name')
    # 用法二 :跨表查询
    publish = serializers.CharField(source='publish.name') # 自动对应成出版社的名字 可以通过 .  跨表查询
    #用法三:表模型中写方法,拿到方法的返回值
    yyy = serializers.CharField(source='get_name')
    ### models.py中
    @property
    def get_name(self):
        return self.name+'sb'
    
    
# 前端看到:
    {
        "xxx": "西游记",
        "price": 199,
        "publish": "南京出版社"
    },

三 高级用法定制字段

-定制返回的字段格式,publish也是一个对象
  		{
            "name": "信息",
            "price": 12,
            "publish": {name:xx,addr:xx}
        }
    
-高级用法定制字段三种方案,目前暂用两种
  -方案一:使用SerializerMethodField 定制
		在序列化类中使用SerializerMethodField
	    publish_detail = serializers.SerializerMethodField()
	    def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么
	        # obj 就是序列化到的book对象
	        return {'name':obj.publish.name,'addr':obj.publish.addr}
    
  -方案二: 在表模型中定制
	-1 表模型中写方法,包装成数据属性
    	@property
        def publish_dict(self):
            return {'name': self.publish.name}
    -2 序列化类中
    	 publish_dict=serializers.DictField()
    	 

四 高级用法定制字段

# 以后一个序列化类,想即做序列化,又做反序列化,会出现问题:字段不匹配,尤其是多表关联的字段

# 有的字段 既做序列化,又做反序列化
	name = serializers.CharField()
    price = serializers.IntegerField()
    
# 有的字段:只做序列化(read_only表示 只做序列化)
	publish_dict = serializers.DictField(read_only=True)  # 只做序列化
    author_list = serializers.ListField(read_only=True)  # 只做序列化
    
# 有的字段只做反序列化(write_only=True)-->是什么类型,取决于前端传入的格式什么样
	publish_id = serializers.IntegerField(write_only=True)  # 反序列化
    authors = serializers.ListField(write_only=True)  # 反序列化
    
    
# 保存方法需要自己重写
	def create(self, validated_data):  # {"name":"一条龙","price":999,"publish":1,"authors":[1,2]}
        authors=validated_data.pop('authors')
        book = Book.objects.create(**validated_data)
        # 增加中间表的记录:图书和作者的关系
        book.authors.add(*authors)  # 向中间表中存入:这个图书关联的做作者

        return book

    
# 笨办法:
	序列化用一个序列化类
	反序列化换另一个序列化类
	

五 反序列化校验总结

-什么情况用反序列化校验?	
	做反序列化的时候,才用----》校验前端传入的数据
	
	-1.API数据处理:当编写API视图函数,接收前端传递的JSON数据时
	-2.表单数据处理:当处理用户提交的表单数据时
	-3.数据创建和更新:在创建或更新数据库记录时
	-4.输入验证:反序列化校验用于验证输入数据的类型、格式和规则
	-5.数据转换:当需要将前端传入的数据转换为内部数据类型(例如日期字符串到日期对象)时
	-6.业务逻辑验证:在处理特定的业务逻辑时
    
-三层校验:
	字段自己:字段类属性---》可控制的比较小
    局部钩子:单个字段校验
    全局钩子:多个字段同时校验

你可能感兴趣的:(python01,django,django,python,windows,pycharm)